diff --git a/forge-core/src/main/java/forge/LobbyPlayer.java b/forge-core/src/main/java/forge/LobbyPlayer.java index 79139ec3a75..3f60952a336 100644 --- a/forge-core/src/main/java/forge/LobbyPlayer.java +++ b/forge-core/src/main/java/forge/LobbyPlayer.java @@ -11,6 +11,7 @@ import org.apache.commons.lang3.StringUtils; public abstract class LobbyPlayer { protected String name; private int avatarIndex = -1; + private int sleeveIndex = -1; private String avatarCardImageKey; public LobbyPlayer(String name) { @@ -59,9 +60,15 @@ public abstract class LobbyPlayer { public int getAvatarIndex() { return avatarIndex; } + public int getSleeveIndex() { + return sleeveIndex; + } public void setAvatarIndex(int avatarIndex) { this.avatarIndex = avatarIndex; } + public void setSleeveIndex(int sleeveIndex) { + this.sleeveIndex = sleeveIndex; + } public String getAvatarCardImageKey() { return avatarCardImageKey; diff --git a/forge-game/src/main/java/forge/game/player/Player.java b/forge-game/src/main/java/forge/game/player/Player.java index 6d5ac51478c..510041f2043 100644 --- a/forge-game/src/main/java/forge/game/player/Player.java +++ b/forge-game/src/main/java/forge/game/player/Player.java @@ -2430,6 +2430,7 @@ public class Player extends GameEntity implements Comparable { controllerCreator = ctrlr; controller = ctrlr; updateAvatar(); + updateSleeve(); view.updateIsAI(this); view.updateLobbyPlayerName(this); } @@ -2439,6 +2440,10 @@ public class Player extends GameEntity implements Comparable { view.updateAvatarCardImageKey(this); } + public void updateSleeve() { + view.updateSleeveIndex(this); + } + /** * Run a procedure using a different controller */ diff --git a/forge-game/src/main/java/forge/game/player/PlayerView.java b/forge-game/src/main/java/forge/game/player/PlayerView.java index 28dfb54c0e3..735c0709f1b 100644 --- a/forge-game/src/main/java/forge/game/player/PlayerView.java +++ b/forge-game/src/main/java/forge/game/player/PlayerView.java @@ -85,6 +85,13 @@ public class PlayerView extends GameEntityView { set(TrackableProperty.AvatarCardImageKey, p.getLobbyPlayer().getAvatarCardImageKey()); } + public int getSleeveIndex() { + return get(TrackableProperty.SleeveIndex); + } + void updateSleeveIndex(Player p) { + set(TrackableProperty.SleeveIndex, p.getLobbyPlayer().getSleeveIndex()); + } + public String getCurrentPlaneName() { return get(TrackableProperty.CurrentPlane); } void updateCurrentPlaneName( String plane ) { set(TrackableProperty.CurrentPlane, plane); diff --git a/forge-game/src/main/java/forge/game/staticability/StaticAbilityCantTarget.java b/forge-game/src/main/java/forge/game/staticability/StaticAbilityCantTarget.java index e58ede1cd8c..00243f7e4c9 100644 --- a/forge-game/src/main/java/forge/game/staticability/StaticAbilityCantTarget.java +++ b/forge-game/src/main/java/forge/game/staticability/StaticAbilityCantTarget.java @@ -124,7 +124,7 @@ public class StaticAbilityCantTarget { } } - return true; + return common(st, spellAbility); } protected static boolean common(final StaticAbility st, final SpellAbility spellAbility) { diff --git a/forge-game/src/main/java/forge/trackable/TrackableProperty.java b/forge-game/src/main/java/forge/trackable/TrackableProperty.java index b19902edcaa..b971b3e37f6 100644 --- a/forge-game/src/main/java/forge/trackable/TrackableProperty.java +++ b/forge-game/src/main/java/forge/trackable/TrackableProperty.java @@ -122,6 +122,7 @@ public enum TrackableProperty { LobbyPlayerName(TrackableTypes.StringType), AvatarIndex(TrackableTypes.IntegerType), AvatarCardImageKey(TrackableTypes.StringType), + SleeveIndex(TrackableTypes.IntegerType), Opponents(TrackableTypes.PlayerViewCollectionType), Life(TrackableTypes.IntegerType), PoisonCounters(TrackableTypes.IntegerType), diff --git a/forge-gui-desktop/src/main/java/forge/GuiDesktop.java b/forge-gui-desktop/src/main/java/forge/GuiDesktop.java index ae3bc960403..b5cdb5b9f70 100644 --- a/forge-gui-desktop/src/main/java/forge/GuiDesktop.java +++ b/forge-gui-desktop/src/main/java/forge/GuiDesktop.java @@ -202,6 +202,14 @@ public class GuiDesktop implements IGuiBase { return 0; } + @Override + public int getSleevesCount() { + if (FSkin.isLoaded()) { + return FSkin.getSleeves().size(); + } + return 0; + } + @Override public String showFileDialog(final String title, final String defaultDir) { final JFileChooser fc = new JFileChooser(defaultDir); diff --git a/forge-gui-desktop/src/main/java/forge/screens/home/PlayerPanel.java b/forge-gui-desktop/src/main/java/forge/screens/home/PlayerPanel.java index c6afcf7e625..dd1639b12ee 100644 --- a/forge-gui-desktop/src/main/java/forge/screens/home/PlayerPanel.java +++ b/forge-gui-desktop/src/main/java/forge/screens/home/PlayerPanel.java @@ -14,6 +14,7 @@ import javax.swing.ButtonGroup; import javax.swing.JCheckBoxMenuItem; import javax.swing.JPopupMenu; +import forge.screens.home.sanctioned.SleeveSelector; import net.miginfocom.swing.MigLayout; import org.apache.commons.lang3.StringUtils; @@ -66,7 +67,8 @@ public class PlayerPanel extends FPanel { private final FLabel nameRandomiser; private final FLabel avatarLabel = new FLabel.Builder().opaque(true).hoverable(true).iconScaleFactor(0.99f).iconInBackground(true).build(); - private int avatarIndex; + private final FLabel sleeveLabel = new FLabel.Builder().opaque(true).hoverable(true).iconScaleFactor(0.99f).iconInBackground(true).build(); + private int avatarIndex, sleeveIndex; private final FTextField txtPlayerName = new FTextField.Builder().build(); private FRadioButton radioHuman; @@ -127,6 +129,10 @@ public class PlayerPanel extends FPanel { createAvatar(); this.add(avatarLabel, "spany 2, width 80px, height 80px"); + /*TODO Layout and Override for PC*/ + //createSleeve(); + //this.add(sleeveLabel, "spany 2, width 60px, height 80px"); + createNameEditor(); this.add(lobby.newLabel(localizer.getMessage("lblName") +":"), "w 40px, h 30px, gaptop 5px"); this.add(txtPlayerName, "h 30px, pushx, growx"); @@ -204,6 +210,10 @@ public class PlayerPanel extends FPanel { avatarLabel.setIcon(FSkin.getAvatars().get(Integer.valueOf(type == LobbySlotType.OPEN ? -1 : avatarIndex))); avatarLabel.repaintSelf(); + sleeveLabel.setEnabled(mayEdit); + sleeveLabel.setIcon(FSkin.getSleeves().get(Integer.valueOf(type == LobbySlotType.OPEN ? -1 : sleeveIndex))); + sleeveLabel.repaintSelf(); + txtPlayerName.setEnabled(mayEdit); txtPlayerName.setText(type == LobbySlotType.OPEN ? StringUtils.EMPTY : playerName); nameRandomiser.setEnabled(mayEdit); @@ -332,6 +342,62 @@ public class PlayerPanel extends FPanel { } }; + /** Listens to sleeve buttons and gives the appropriate player focus. */ + private final FocusAdapter sleeveFocusListener = new FocusAdapter() { + @Override + public void focusGained(final FocusEvent e) { + lobby.changePlayerFocus(index); + } + }; + + private final FMouseAdapter sleeveMouseListener = new FMouseAdapter() { + @Override public final void onLeftClick(final MouseEvent e) { + if (!sleeveLabel.isEnabled()) { + return; + } + + final FLabel sleeve = (FLabel)e.getSource(); + + lobby.changePlayerFocus(index); + sleeve.requestFocusInWindow(); + + final SleeveSelector sSel = new SleeveSelector(playerName, sleeveIndex, lobby.getUsedSleeves()); + for (final FLabel lbl : sSel.getSelectables()) { + lbl.setCommand(new UiCommand() { + @Override + public void run() { + setSleeveIndex(Integer.valueOf(lbl.getName().substring(11))); + sSel.setVisible(false); + } + }); + } + + sSel.setVisible(true); + sSel.dispose(); + + if (index < 2) { + lobby.updateSleevePrefs(); + } + + lobby.firePlayerChangeListener(index); + } + + @Override public final void onRightClick(final MouseEvent e) { + if (!sleeveLabel.isEnabled()) { + return; + } + + lobby.changePlayerFocus(index); + sleeveLabel.requestFocusInWindow(); + + setRandomSleeve(); + + if (index < 2) { + lobby.updateSleevePrefs(); + } + } + }; + private void updateVariantControlsVisibility() { final boolean isOathbreaker = lobby.hasVariant(GameType.Oathbreaker); final boolean isTinyLeaders = lobby.hasVariant(GameType.TinyLeaders); @@ -703,6 +769,20 @@ public class PlayerPanel extends FPanel { avatarLabel.addMouseListener(avatarMouseListener); } + private void createSleeve() { + final String[] currentPrefs = FModel.getPreferences().getPref(FPref.UI_SLEEVES).split(","); + if (index < currentPrefs.length) { + sleeveIndex = Integer.parseInt(currentPrefs[index]); + sleeveLabel.setIcon(FSkin.getSleeves().get(sleeveIndex)); + } else { + setRandomSleeve(false); + } + + sleeveLabel.setToolTipText("L-click: Select sleeve. R-click: Randomize sleeve."); + sleeveLabel.addFocusListener(sleeveFocusListener); + sleeveLabel.addMouseListener(sleeveMouseListener); + } + /** Applies a random avatar, avoiding avatars already used. */ private void setRandomAvatar() { setRandomAvatar(true); @@ -721,6 +801,24 @@ public class PlayerPanel extends FPanel { } } + /** Applies a random sleeve, avoiding sleeve already used. */ + private void setRandomSleeve() { + setRandomSleeve(true); + } + private void setRandomSleeve(final boolean fireListeners) { + int random = 0; + + final List usedSleeves = lobby.getUsedSleeves(); + do { + random = MyRandom.getRandom().nextInt(FSkin.getSleeves().size()); + } while (usedSleeves.contains(random)); + setSleeveIndex(random); + + if (fireListeners) { + lobby.firePlayerChangeListener(index); + } + } + private final FSkin.LineSkinBorder focusedBorder = new FSkin.LineSkinBorder(FSkin.getColor(FSkin.Colors.CLR_BORDERS).alphaColor(255), 3); private final FSkin.LineSkinBorder defaultBorder = new FSkin.LineSkinBorder(FSkin.getColor(FSkin.Colors.CLR_THEME).alphaColor(200), 2); @@ -746,6 +844,16 @@ public class PlayerPanel extends FPanel { avatarLabel.repaintSelf(); } + public int getSleeveIndex() { + return sleeveIndex; + } + public void setSleeveIndex(final int sleeveIndex0) { + sleeveIndex = sleeveIndex0; + final SkinImage icon = FSkin.getSleeves().get(sleeveIndex); + sleeveLabel.setIcon(icon); + sleeveLabel.repaintSelf(); + } + public int getTeam() { return teamComboBox.getSelectedIndex(); } diff --git a/forge-gui-desktop/src/main/java/forge/screens/home/VLobby.java b/forge-gui-desktop/src/main/java/forge/screens/home/VLobby.java index 7c0c978b0be..5a58fa25598 100644 --- a/forge-gui-desktop/src/main/java/forge/screens/home/VLobby.java +++ b/forge-gui-desktop/src/main/java/forge/screens/home/VLobby.java @@ -397,7 +397,7 @@ public class VLobby implements ILobbyView { private UpdateLobbyPlayerEvent getSlot(final int index) { final PlayerPanel panel = playerPanels.get(index); - return UpdateLobbyPlayerEvent.create(panel.getType(), panel.getPlayerName(), panel.getAvatarIndex(), panel.getTeam(), panel.isArchenemy(), panel.isReady(), panel.isDevMode(), panel.getAiOptions()); + return UpdateLobbyPlayerEvent.create(panel.getType(), panel.getPlayerName(), panel.getAvatarIndex(), -1/*TODO panel.getSleeveIndex()*/, panel.getTeam(), panel.isArchenemy(), panel.isReady(), panel.isDevMode(), panel.getAiOptions()); } /** Builds the actual deck panel layouts for each player. @@ -858,6 +858,15 @@ public class VLobby implements ILobbyView { prefs.save(); } + /** Saves sleeve prefs for players one and two. */ + void updateSleevePrefs() { + final int pOneIndex = playerPanels.get(0).getSleeveIndex(); + final int pTwoIndex = playerPanels.get(1).getSleeveIndex(); + + prefs.setPref(FPref.UI_SLEEVES, pOneIndex + "," + pTwoIndex); + prefs.save(); + } + /** Adds a pre-styled FLabel component with the specified title. */ FLabel newLabel(final String title) { return new FLabel.Builder().text(title).fontSize(14).fontStyle(Font.ITALIC).build(); @@ -871,6 +880,14 @@ public class VLobby implements ILobbyView { return usedAvatars; } + List getUsedSleeves() { + final List usedSleeves = Lists.newArrayListWithCapacity(MAX_PLAYERS); + for (final PlayerPanel pp : playerPanels) { + usedSleeves.add(pp.getSleeveIndex()); + } + return usedSleeves; + } + private static final ImmutableList genderOptions = ImmutableList.of("Male", "Female", "Any"), typeOptions = ImmutableList.of("Fantasy", "Generic", "Any"); diff --git a/forge-gui-desktop/src/main/java/forge/screens/home/sanctioned/SleeveSelector.java b/forge-gui-desktop/src/main/java/forge/screens/home/sanctioned/SleeveSelector.java new file mode 100644 index 00000000000..91fb09361ee --- /dev/null +++ b/forge-gui-desktop/src/main/java/forge/screens/home/sanctioned/SleeveSelector.java @@ -0,0 +1,71 @@ +package forge.screens.home.sanctioned; + +import forge.gui.WrapLayout; +import forge.toolbox.FLabel; +import forge.toolbox.FScrollPane; +import forge.toolbox.FSkin; +import forge.view.FDialog; + +import javax.swing.*; +import java.awt.*; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Map; + +@SuppressWarnings("serial") +public class SleeveSelector extends FDialog { + private final List selectables = new ArrayList<>(); + private final Map sleeveMap = FSkin.getSleeves(); + + public SleeveSelector(final String playerName, final int currentIndex, final Collection usedIndices) { + this.setTitle("Select Sleeve for " + playerName); + + final JPanel pnlSleevePics = new JPanel(new WrapLayout()); + + pnlSleevePics.setOpaque(false); + pnlSleevePics.setOpaque(false); + + final FLabel initialSelection = makeSleeveLabel(sleeveMap.get(currentIndex), currentIndex, currentIndex); + pnlSleevePics.add(initialSelection); + for (final Integer i : sleeveMap.keySet()) { + if (currentIndex != i) { + pnlSleevePics.add(makeSleeveLabel(sleeveMap.get(i), i, currentIndex)); + } + } + + final int width = this.getOwner().getWidth() * 3 / 4; + final int height = this.getOwner().getHeight() * 3 / 4; + this.setPreferredSize(new Dimension(width, height)); + this.setSize(width, height); + + final FScrollPane scroller = new FScrollPane(pnlSleevePics, false); + scroller.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER); + this.add(scroller, "w 100%-24px!, pushy, growy, gap 12px 0 0 0"); + this.setDefaultFocus(initialSelection); + } + + private FLabel makeSleeveLabel(final FSkin.SkinImage img0, final int index0, final int oldIndex) { + final FLabel lbl = new FLabel.Builder().icon(img0).iconScaleFactor(0.95).iconAlignX(SwingConstants.CENTER) + .iconInBackground(true).hoverable(true).selectable(true).selected(oldIndex == index0) + .unhoveredAlpha(oldIndex == index0 ? 0.9f : 0.7f).build(); + + final Dimension size = new Dimension(60, 80); + lbl.setPreferredSize(size); + lbl.setMaximumSize(size); + lbl.setMinimumSize(size); + lbl.setName("SleeveLabel" + index0); + + if (oldIndex == index0) { + lbl.setBorder(new FSkin.LineSkinBorder(FSkin.getColor(FSkin.Colors.CLR_BORDERS).alphaColor(255), 3)); + } + + selectables.add(lbl); + + return lbl; + } + + public List getSelectables() { + return this.selectables; + } +} diff --git a/forge-gui-desktop/src/main/java/forge/toolbox/FSkin.java b/forge-gui-desktop/src/main/java/forge/toolbox/FSkin.java index f7e658da7ae..b0ecc7338b4 100644 --- a/forge-gui-desktop/src/main/java/forge/toolbox/FSkin.java +++ b/forge-gui-desktop/src/main/java/forge/toolbox/FSkin.java @@ -859,6 +859,7 @@ public class FSkin { } private static Map avatars; + private static Map sleeves; private static Map fixedFonts = new HashMap<>(); public static Font getFixedFont() { @@ -1039,7 +1040,7 @@ public class FSkin { private static String preferredDir; private static String preferredName; private static BufferedImage bimDefaultSprite, bimFavIcon, bimPreferredSprite, bimFoils, bimQuestDraftDeck, - bimOldFoils, bimDefaultAvatars, bimPreferredAvatars, bimTrophies, bimAbilities, bimManaIcons; + bimOldFoils, bimDefaultAvatars, bimPreferredAvatars, bimTrophies, bimAbilities, bimManaIcons, bimDefaultSleeve, bimDefaultSleeve2; private static int x0, y0, w0, h0, newW, newH, preferredW, preferredH; private static int[] tempCoords; private static int defaultFontSize = 12; @@ -1173,6 +1174,8 @@ public class FSkin { final File f9 = new File(defaultDir + ForgeConstants.SPRITE_FAVICONS_FILE); final File f10 = new File(defaultDir + ForgeConstants.SPRITE_ABILITY_FILE); final File f11 = new File(defaultDir + ForgeConstants.SPRITE_MANAICONS_FILE); + final File f12 = new File(defaultDir + ForgeConstants.SPRITE_SLEEVES_FILE); + final File f13 = new File(defaultDir + ForgeConstants.SPRITE_SLEEVES2_FILE); try { int p = 0; @@ -1190,6 +1193,10 @@ public class FSkin { FView.SINGLETON_INSTANCE.incrementSplashProgessBar(++p); bimDefaultAvatars = ImageIO.read(f4); FView.SINGLETON_INSTANCE.incrementSplashProgessBar(++p); + bimDefaultSleeve = ImageIO.read(f12); + FView.SINGLETON_INSTANCE.incrementSplashProgessBar(++p); + bimDefaultSleeve2 = ImageIO.read(f13); + FView.SINGLETON_INSTANCE.incrementSplashProgessBar(++p); bimTrophies = ImageIO.read(f7); FView.SINGLETON_INSTANCE.incrementSplashProgessBar(++p); bimQuestDraftDeck = ImageIO.read(f8); @@ -1255,6 +1262,8 @@ public class FSkin { // Assemble avatar images assembleAvatars(); + // Sleeves + assembleSleeves(); // Images loaded; can start UI init. FView.SINGLETON_INSTANCE.setSplashProgessBarMessage("Creating display components."); @@ -1266,6 +1275,8 @@ public class FSkin { bimOldFoils.flush(); bimPreferredSprite.flush(); bimDefaultAvatars.flush(); + bimDefaultSleeve.flush(); + bimDefaultSleeve2.flush(); bimQuestDraftDeck.flush(); bimTrophies.flush(); bimAbilities.flush(); @@ -1278,6 +1289,8 @@ public class FSkin { bimOldFoils = null; bimPreferredSprite = null; bimDefaultAvatars = null; + bimDefaultSleeve = null; + bimDefaultSleeve2 = null; bimPreferredAvatars = null; bimQuestDraftDeck = null; bimTrophies = null; @@ -1379,6 +1392,10 @@ public class FSkin { return avatars; } + public static Map getSleeves() { + return sleeves; + } + public static boolean isLoaded() { return loaded; } /** @@ -1482,6 +1499,34 @@ public class FSkin { } } + private static void assembleSleeves() { + sleeves = new HashMap<>(); + int counter = 0; + Color pxTest; + + final int pw = bimDefaultSleeve.getWidth(); + final int ph = bimDefaultSleeve.getHeight(); + + for (int j = 0; j < ph; j += 500) { + for (int i = 0; i < pw; i += 360) { + pxTest = getColorFromPixel(bimDefaultSleeve.getRGB(i + 180, j + 250)); + if (pxTest.getAlpha() == 0) { continue; } + sleeves.put(counter++, new SkinImage(bimDefaultSleeve.getSubimage(i, j, 360, 500))); + } + } + //2nd set + final int aw = bimDefaultSleeve2.getWidth(); + final int ah = bimDefaultSleeve2.getHeight(); + + for (int j = 0; j < ah; j += 500) { + for (int i = 0; i < aw; i += 360) { + pxTest = getColorFromPixel(bimDefaultSleeve2.getRGB(i + 180, j + 250)); + if (pxTest.getAlpha() == 0) { continue; } + sleeves.put(counter++, new SkinImage(bimDefaultSleeve2.getSubimage(i, j, 360, 500))); + } + } + } + private static void setImage(final FSkinProp s0, final BufferedImage bim) { tempCoords = s0.getCoords(); x0 = tempCoords[0]; diff --git a/forge-gui-mobile/src/forge/GuiMobile.java b/forge-gui-mobile/src/forge/GuiMobile.java index d56c764a639..3843b3c2cec 100644 --- a/forge-gui-mobile/src/forge/GuiMobile.java +++ b/forge-gui-mobile/src/forge/GuiMobile.java @@ -244,6 +244,14 @@ public class GuiMobile implements IGuiBase { return 0; } + @Override + public int getSleevesCount() { + if (FSkin.isLoaded()) { + return FSkin.getSleeves().size(); + } + return 0; + } + @Override public String showFileDialog(final String title, final String defaultDir) { return ForgeConstants.USER_GAMES_DIR + "Test.fgs"; //TODO: Show dialog diff --git a/forge-gui-mobile/src/forge/assets/FSkin.java b/forge-gui-mobile/src/forge/assets/FSkin.java index 9ed94ee43c3..053fdb349ea 100644 --- a/forge-gui-mobile/src/forge/assets/FSkin.java +++ b/forge-gui-mobile/src/forge/assets/FSkin.java @@ -1,11 +1,10 @@ package forge.assets; -import java.util.ArrayList; -import java.util.Collections; import java.util.HashMap; -import java.util.List; import java.util.Map; +import com.badlogic.gdx.utils.Array; +import forge.Forge; import org.apache.commons.lang3.text.WordUtils; import com.badlogic.gdx.Gdx; @@ -30,8 +29,10 @@ import forge.toolbox.FProgressBar; public class FSkin { private static final Map images = new HashMap<>(); private static final Map avatars = new HashMap<>(); + private static final Map sleeves = new HashMap<>(); + private static final Map borders = new HashMap<>(); - private static List allSkins; + private static Array allSkins; private static FileHandle preferredDir; private static String preferredName; private static boolean loaded = false; @@ -98,12 +99,12 @@ public class FSkin { else { if (splashScreen != null) { if (allSkins == null) { //initialize - allSkins = new ArrayList<>(); - final List skinDirectoryNames = getSkinDirectoryNames(); + allSkins = new Array<>(); + final Array skinDirectoryNames = getSkinDirectoryNames(); for (final String skinDirectoryName : skinDirectoryNames) { allSkins.add(WordUtils.capitalize(skinDirectoryName.replace('_', ' '))); } - Collections.sort(allSkins); + allSkins.sort(); } } @@ -172,6 +173,9 @@ public class FSkin { } avatars.clear(); + sleeves.clear(); + + boolean textureFilter = Forge.isTextureFilteringEnabled(); final Map textures = new HashMap<>(); @@ -183,6 +187,9 @@ public class FSkin { final FileHandle f5 = getSkinFile(ForgeConstants.SPRITE_AVATARS_FILE); final FileHandle f6 = getDefaultSkinFile(SourceFile.OLD_FOILS.getFilename()); final FileHandle f7 = getDefaultSkinFile(ForgeConstants.SPRITE_MANAICONS_FILE); + final FileHandle f8 = getDefaultSkinFile(ForgeConstants.SPRITE_SLEEVES_FILE); + final FileHandle f9 = getDefaultSkinFile(ForgeConstants.SPRITE_SLEEVES2_FILE); + final FileHandle f10 = getDefaultSkinFile(ForgeConstants.SPRITE_BORDER_FILE); try { textures.put(f1.path(), new Texture(f1)); @@ -218,16 +225,25 @@ public class FSkin { //assemble avatar textures int counter = 0; + int scount = 0; Color pxTest; - Pixmap pxDefaultAvatars, pxPreferredAvatars; - Texture txDefaultAvatars, txPreferredAvatars; + Pixmap pxDefaultAvatars, pxPreferredAvatars, pxDefaultSleeves; + Texture txDefaultAvatars, txPreferredAvatars, txDefaultSleeves; pxDefaultAvatars = new Pixmap(f4); - txDefaultAvatars = new Texture(f4); + pxDefaultSleeves = new Pixmap(f8); + txDefaultAvatars = new Texture(f4, textureFilter); + if (textureFilter) + txDefaultAvatars.setFilter(Texture.TextureFilter.MipMapLinearLinear, Texture.TextureFilter.Linear); + txDefaultSleeves = new Texture(f8, textureFilter); + if (textureFilter) + txDefaultSleeves.setFilter(Texture.TextureFilter.MipMapLinearLinear, Texture.TextureFilter.Linear); if (f5.exists()) { pxPreferredAvatars = new Pixmap(f5); - txPreferredAvatars = new Texture(f5); + txPreferredAvatars = new Texture(f5, textureFilter); + if (textureFilter) + txPreferredAvatars.setFilter(Texture.TextureFilter.MipMapLinearLinear, Texture.TextureFilter.Linear); final int pw = pxPreferredAvatars.getWidth(); final int ph = pxPreferredAvatars.getHeight(); @@ -255,8 +271,42 @@ public class FSkin { } } + + final int sw = pxDefaultSleeves.getWidth(); + final int sh = pxDefaultSleeves.getHeight(); + + for (int j = 0; j < sh; j += 500) { + for (int i = 0; i < sw; i += 360) { + pxTest = new Color(pxDefaultSleeves.getPixel(i + 180, j + 250)); + if (pxTest.a == 0) { continue; } + FSkin.sleeves.put(scount++, new TextureRegion(txDefaultSleeves, i, j, 360, 500)); + } + } + + //re init second set of sleeves + pxDefaultSleeves = new Pixmap(f9); + txDefaultSleeves = new Texture(f9, textureFilter); + if (textureFilter) + txDefaultSleeves.setFilter(Texture.TextureFilter.MipMapLinearLinear, Texture.TextureFilter.Linear); + + final int sw2 = pxDefaultSleeves.getWidth(); + final int sh2 = pxDefaultSleeves.getHeight(); + + for (int j = 0; j < sh2; j += 500) { + for (int i = 0; i < sw2; i += 360) { + pxTest = new Color(pxDefaultSleeves.getPixel(i + 180, j + 250)); + if (pxTest.a == 0) { continue; } + FSkin.sleeves.put(scount++, new TextureRegion(txDefaultSleeves, i, j, 360, 500)); + } + } + + Texture bordersBW = new Texture(f10); + FSkin.borders.put(0, new TextureRegion(bordersBW, 2, 2, 672, 936)); + FSkin.borders.put(1, new TextureRegion(bordersBW, 676, 2, 672, 936)); + preferredIcons.dispose(); pxDefaultAvatars.dispose(); + pxDefaultSleeves.dispose();; } catch (final Exception e) { System.err.println("FSkin$loadFull: Missing a sprite (default icons, " @@ -314,8 +364,8 @@ public class FSkin { * * @return the skins */ - public static List getSkinDirectoryNames() { - final List mySkins = new ArrayList<>(); + public static Array getSkinDirectoryNames() { + final Array mySkins = new Array<>(); final FileHandle dir = Gdx.files.absolute(ForgeConstants.SKINS_DIR); for (FileHandle skinFile : dir.list()) { @@ -340,5 +390,13 @@ public class FSkin { return avatars; } + public static Map getSleeves() { + return sleeves; + } + + public static Map getBorders() { + return borders; + } + public static boolean isLoaded() { return loaded; } } diff --git a/forge-gui-mobile/src/forge/assets/ImageCache.java b/forge-gui-mobile/src/forge/assets/ImageCache.java index 5c7f63dfd99..2ea5a109f4e 100644 --- a/forge-gui-mobile/src/forge/assets/ImageCache.java +++ b/forge-gui-mobile/src/forge/assets/ImageCache.java @@ -214,6 +214,16 @@ public class ImageCache { return Color.valueOf("#fffffd"); return Color.valueOf("#171717"); } + public static int getFSkinBorders(CardView c) { + if (c == null) + return 0; + + CardView.CardStateView state = c.getCurrentState(); + CardEdition ed = FModel.getMagicDb().getEditions().get(state.getSetCode()); + if (ed != null && ed.isWhiteBorder() && state.getFoilIndex() == 0) + return 1; + return 0; + } public static boolean isExtendedArt(CardView c) { if (c == null) return false; diff --git a/forge-gui-mobile/src/forge/card/CardImageRenderer.java b/forge-gui-mobile/src/forge/card/CardImageRenderer.java index 732427443eb..e6b40f07938 100644 --- a/forge-gui-mobile/src/forge/card/CardImageRenderer.java +++ b/forge-gui-mobile/src/forge/card/CardImageRenderer.java @@ -6,7 +6,10 @@ import com.badlogic.gdx.utils.Align; import com.google.common.collect.ImmutableList; import forge.Forge; import forge.Graphics; +import forge.ImageKeys; import forge.assets.FBufferedImage; +import forge.assets.FImage; +import forge.assets.FSkin; import forge.assets.FSkinColor; import forge.assets.FSkinFont; import forge.assets.FSkinImage; @@ -326,7 +329,9 @@ public class CardImageRenderer { } public static void drawZoom(Graphics g, CardView card, GameView gameView, boolean altState, float x, float y, float w, float h, float dispW, float dispH, boolean isCurrentCard) { + boolean canshow = MatchController.instance.mayView(card); final Texture image = ImageCache.getImage(card.getState(altState).getImageKey(MatchController.instance.getLocalPlayers()), true); + FImage sleeves = MatchController.getPlayerSleeve(card.getOwner()); if (image == null) { //draw details if can't draw zoom drawDetails(g, card, gameView, altState, x, y, w, h); return; @@ -337,8 +342,6 @@ public class CardImageRenderer { return; } - boolean canLook = MatchController.instance.mayView(card); - if (image == ImageCache.defaultImage) { //support drawing card image manually if card image not found drawCardImage(g, card, altState, x, y, w, h, CardStackPosition.Top); } @@ -358,47 +361,43 @@ public class CardImageRenderer { if (ImageCache.isExtendedArt(card)) g.drawRotatedImage(image, new_x, new_y, new_w, new_h, new_x + new_w / 2, new_y + new_h / 2, -90); else { - if (rotatePlane) - g.drawfillBorder(3, ImageCache.borderColor(card), new_xRotate, new_yRotate, new_h, new_w, radius); - else - g.drawfillBorder(3, ImageCache.borderColor(card), x, y, w, h, radius); - - g.drawRotatedImage(ImageCache.croppedBorderImage(image), new_x+radius/2.3f, new_y+radius/2, new_w*0.96f, new_h*0.96f, (new_x+radius/2.3f) + (new_w*0.96f) / 2, (new_y+radius/2) + (new_h*0.96f) / 2, -90); + g.drawRotatedImage(FSkin.getBorders().get(0), new_x, new_y, new_w, new_h, new_x + new_w / 2, new_y + new_h / 2, -90); + g.drawRotatedImage(ImageCache.croppedBorderImage(image), new_x+radius/2, new_y+radius/2, new_w*0.96f, new_h*0.96f, (new_x+radius/2) + (new_w*0.96f) / 2, (new_y+radius/2) + (new_h*0.96f) / 2, -90); } } else g.drawRotatedImage(image, new_x, new_y, new_w, new_h, new_x + new_w / 2, new_y + new_h / 2, -90); - } else if (rotateSplit && isCurrentCard && card.isSplitCard() && canLook) { + } else if (rotateSplit && isCurrentCard && card.isSplitCard() && canshow) { boolean isAftermath = card.getText().contains("Aftermath") || card.getAlternateState().getOracleText().contains("Aftermath"); if (Forge.enableUIMask) { if (ImageCache.isExtendedArt(card)) g.drawRotatedImage(image, new_x, new_y, new_w, new_h, new_x + new_w / 2, new_y + new_h / 2, isAftermath ? 90 : -90); else { - if (rotateSplit) - g.drawfillBorder(3, ImageCache.borderColor(card), new_xRotate, new_yRotate, new_h, new_w, radius); - else - g.drawfillBorder(3, ImageCache.borderColor(card), x, y, w, h, radius); - - g.drawRotatedImage(ImageCache.croppedBorderImage(image), new_x + radius / 2.3f, new_y + radius / 2, new_w * 0.96f, new_h * 0.96f, (new_x + radius / 2.3f) + (new_w * 0.96f) / 2, (new_y + radius / 2) + (new_h * 0.96f) / 2, isAftermath ? 90 : -90); + g.drawRotatedImage(FSkin.getBorders().get(ImageCache.getFSkinBorders(card)), new_x, new_y, new_w, new_h, new_x + new_w / 2, new_y + new_h / 2, isAftermath ? 90 : -90); + g.drawRotatedImage(ImageCache.croppedBorderImage(image), new_x + radius / 2, new_y + radius / 2, new_w * 0.96f, new_h * 0.96f, (new_x + radius / 2) + (new_w * 0.96f) / 2, (new_y + radius / 2) + (new_h * 0.96f) / 2, isAftermath ? 90 : -90); } } else g.drawRotatedImage(image, new_x, new_y, new_w, new_h, new_x + new_w / 2, new_y + new_h / 2, isAftermath ? 90 : -90); } else { - if (Forge.enableUIMask) { + if (Forge.enableUIMask && canshow && !ImageKeys.getTokenKey(ImageKeys.MORPH_IMAGE).equals(card.getState(altState).getImageKey())) { if (ImageCache.isExtendedArt(card)) g.drawImage(image, x, y, w, h); else { - g.drawImage(ImageCache.getBorderImage(card, canLook), x, y, w, h); + g.drawImage(ImageCache.getBorderImage(card, canshow), x, y, w, h); g.drawImage(ImageCache.croppedBorderImage(image), x + radius / 2.4f, y + radius / 2, w * 0.96f, h * 0.96f); } } - else - g.drawImage(image, x, y, w, h); + else { + if (canshow && !ImageKeys.getTokenKey(ImageKeys.MORPH_IMAGE).equals(card.getState(altState).getImageKey())) + g.drawImage(image, x, y, w, h); + else // sleeve + g.drawImage(sleeves, x, y, w, h); + } } } - CardRenderer.drawFoilEffect(g, card, x, y, w, h, isCurrentCard && canLook && image != ImageCache.defaultImage); + CardRenderer.drawFoilEffect(g, card, x, y, w, h, isCurrentCard && canshow && image != ImageCache.defaultImage); } public static void drawDetails(Graphics g, CardView card, GameView gameView, boolean altState, float x, float y, float w, float h) { diff --git a/forge-gui-mobile/src/forge/card/CardRenderer.java b/forge-gui-mobile/src/forge/card/CardRenderer.java index 77fae4d5bd1..113a7176796 100644 --- a/forge-gui-mobile/src/forge/card/CardRenderer.java +++ b/forge-gui-mobile/src/forge/card/CardRenderer.java @@ -19,9 +19,12 @@ import forge.CachedCardImage; import forge.Forge; import forge.FThreads; import forge.Graphics; +import forge.ImageKeys; import forge.StaticData; +import forge.assets.FImage; import forge.assets.FImageComplex; import forge.assets.FRotatedImage; +import forge.assets.FSkin; import forge.assets.FSkinColor; import forge.assets.FSkinFont; import forge.assets.FSkinImage; @@ -430,7 +433,9 @@ public class CardRenderer { } } public static void drawCard(Graphics g, CardView card, float x, float y, float w, float h, CardStackPosition pos, boolean rotate) { + boolean canshow = MatchController.instance.mayView(card) && !ImageKeys.getTokenKey(ImageKeys.MORPH_IMAGE).equals(card.getCurrentState().getImageKey()); Texture image = new RendererCachedCardImage(card, false).getImage(); + FImage sleeves = MatchController.getPlayerSleeve(card.getOwner()); float radius = (h - w)/8; if (image != null) { @@ -444,7 +449,7 @@ public class CardRenderer { if (ImageCache.isExtendedArt(card)) g.drawRotatedImage(image, x, y, w, h, x + w / 2, y + h / 2, -90); else { - g.drawfillBorder(3, ImageCache.borderColor(card), x, y, w, h, radius); + g.drawRotatedImage(FSkin.getBorders().get(0), x, y, w, h, x + w / 2, y + h / 2, -90); g.drawRotatedImage(ImageCache.croppedBorderImage(image), x+radius/2.3f, y+radius/2, w*0.96f, h*0.96f, (x+radius/2.3f) + (w*0.96f) / 2, (y+radius/2) + (h*0.96f) / 2, -90); } } @@ -452,17 +457,21 @@ public class CardRenderer { g.drawRotatedImage(image, x, y, w, h, x + w / 2, y + h / 2, -90); } else { - if (Forge.enableUIMask) { + if (Forge.enableUIMask && canshow) { if (ImageCache.isExtendedArt(card)) g.drawImage(image, x, y, w, h); else { boolean t = (card.getCurrentState().getOriginalColors() != card.getCurrentState().getColors()) || card.getCurrentState().hasChangeColors(); - g.drawBorderImage(ImageCache.getBorderImage(card, MatchController.instance.mayView(card)), ImageCache.getTint(card), x, y, w, h, t); //tint check for changed colors + g.drawBorderImage(ImageCache.getBorderImage(card, canshow), ImageCache.getTint(card), x, y, w, h, t); //tint check for changed colors g.drawImage(ImageCache.croppedBorderImage(image), x + radius / 2.4f, y + radius / 2, w * 0.96f, h * 0.96f); } } - else - g.drawImage(image, x, y, w, h); + else { + if (canshow) + g.drawImage(image, x, y, w, h); + else // draw card back sleeves + g.drawImage(sleeves, x, y, w, h); + } } } drawFoilEffect(g, card, x, y, w, h, false); @@ -1113,11 +1122,15 @@ public class CardRenderer { } public static void drawFoilEffect(Graphics g, CardView card, float x, float y, float w, float h, boolean inZoomer) { + float new_x = x; float new_y = y; float new_w = w; float new_h = h; float radius = (h - w)/8; + if (Forge.enableUIMask) { + new_x += radius/2.4f; new_y += radius/2; new_w = w * 0.96f; new_h = h * 0.96f; + } if (isPreferenceEnabled(FPref.UI_OVERLAY_FOIL_EFFECT) && MatchController.instance.mayView(card)) { boolean rotateSplit = isPreferenceEnabled(FPref.UI_ROTATE_SPLIT_CARDS) && card.isSplitCard() && inZoomer; int foil = card.getCurrentState().getFoilIndex(); if (foil > 0) { - CardFaceSymbols.drawOther(g, String.format("foil%02d", foil), x, y, w, h, rotateSplit); + CardFaceSymbols.drawOther(g, String.format("foil%02d", foil), new_x, new_y, new_w, new_h, rotateSplit); } } } diff --git a/forge-gui-mobile/src/forge/screens/constructed/AvatarSelector.java b/forge-gui-mobile/src/forge/screens/constructed/AvatarSelector.java index 5fa5dfac739..a4de6366815 100644 --- a/forge-gui-mobile/src/forge/screens/constructed/AvatarSelector.java +++ b/forge-gui-mobile/src/forge/screens/constructed/AvatarSelector.java @@ -37,7 +37,7 @@ public class AvatarSelector extends FScreen { } private static final float PADDING = Utils.scale(5); - private static final int COLUMNS = 4; + private static final int COLUMNS = 5; private final int currentIndex; private final List usedAvatars; diff --git a/forge-gui-mobile/src/forge/screens/constructed/LobbyScreen.java b/forge-gui-mobile/src/forge/screens/constructed/LobbyScreen.java index 31685d17257..46b5f53cf11 100644 --- a/forge-gui-mobile/src/forge/screens/constructed/LobbyScreen.java +++ b/forge-gui-mobile/src/forge/screens/constructed/LobbyScreen.java @@ -301,13 +301,20 @@ public abstract class LobbyScreen extends LaunchScreen implements ILobbyView { } /** Saves avatar prefs for players one and two. */ - void updateAvatarPrefs() { + void updateAvatarPrefs() { int pOneIndex = playerPanels.get(0).getAvatarIndex(); int pTwoIndex = playerPanels.get(1).getAvatarIndex(); prefs.setPref(FPref.UI_AVATARS, pOneIndex + "," + pTwoIndex); prefs.save(); } + void updateSleevePrefs() { + int pOneIndex = playerPanels.get(0).getSleeveIndex(); + int pTwoIndex = playerPanels.get(1).getSleeveIndex(); + + prefs.setPref(FPref.UI_SLEEVES, pOneIndex + "," + pTwoIndex); + prefs.save(); + } /** Updates the avatars from preferences on update. */ private void updatePlayersFromPrefs() { @@ -320,6 +327,13 @@ public abstract class LobbyScreen extends LaunchScreen implements ILobbyView { playerPanels.get(i).setAvatarIndex(avatarIndex); } + // Sleeves + String[] sleevePrefs = prefs.getPref(FPref.UI_SLEEVES).split(","); + for (int i = 0; i < sleevePrefs.length; i++) { + int sleeveIndex = Integer.parseInt(sleevePrefs[i]); + playerPanels.get(i).setSleeveIndex(sleeveIndex); + } + // Name String prefName = prefs.getPref(FPref.PLAYER_NAME); playerPanels.get(0).setPlayerName(StringUtils.isBlank(prefName) ? Localizer.getInstance().getMessage("lblHuman") : prefName); @@ -334,6 +348,15 @@ public abstract class LobbyScreen extends LaunchScreen implements ILobbyView { return usedAvatars; } + List getUsedSleeves() { + List usedSleeves = Arrays.asList(-1,-1,-1,-1,-1,-1,-1,-1); + int i = 0; + for (PlayerPanel pp : playerPanels) { + usedSleeves.set(i++, pp.getSleeveIndex()); + } + return usedSleeves; + } + List getPlayerNames() { List names = new ArrayList<>(); for (PlayerPanel pp : playerPanels) { @@ -350,6 +373,10 @@ public abstract class LobbyScreen extends LaunchScreen implements ILobbyView { return playerPanels.get(i).getAvatarIndex(); } + public int getPlayerSleeve(int i) { + return playerPanels.get(i).getSleeveIndex(); + } + ///////////////////////////////////////////// //========== Various listeners in build order @@ -527,8 +554,18 @@ public abstract class LobbyScreen extends LaunchScreen implements ILobbyView { final LobbySlotType type = slot.getType(); panel.setType(type); - panel.setPlayerName(slot.getName()); - panel.setAvatarIndex(slot.getAvatarIndex()); + if (type != LobbySlotType.AI) { + panel.setPlayerName(slot.getName()); + panel.setAvatarIndex(slot.getAvatarIndex()); + panel.setSleeveIndex(slot.getSleeveIndex()); + } else { + //AI: this one overrides the setplayername if blank + if (panel.getPlayerName().isEmpty()) + panel.setPlayerName(slot.getName()); + //AI: override settings if somehow player changes it for AI + slot.setAvatarIndex(panel.getAvatarIndex()); + slot.setSleeveIndex(panel.getSleeveIndex()); + } panel.setTeam(slot.getTeam()); panel.setIsReady(slot.isReady()); panel.setIsDevMode(slot.isDevMode()); @@ -631,6 +668,18 @@ public abstract class LobbyScreen extends LaunchScreen implements ILobbyView { } } + void updateAvatar(final int index, final int avatarIndex) { + if (playerChangeListener != null) { + playerChangeListener.update(index, UpdateLobbyPlayerEvent.avatarUpdate(avatarIndex)); + } + } + + void updateSleeve(final int index, final int sleeveIndex) { + if (playerChangeListener != null) { + playerChangeListener.update(index, UpdateLobbyPlayerEvent.sleeveUpdate(sleeveIndex)); + } + } + void setReady(final int index, final boolean ready) { if (ready) { updateDeck(index); @@ -667,7 +716,7 @@ public abstract class LobbyScreen extends LaunchScreen implements ILobbyView { private UpdateLobbyPlayerEvent getSlot(final int index) { final PlayerPanel panel = playerPanels.get(index); - return UpdateLobbyPlayerEvent.create(panel.getType(), panel.getPlayerName(), panel.getAvatarIndex(), panel.getTeam(), panel.isArchenemy(), panel.isReady(), panel.isDevMode(), panel.getAiOptions()); + return UpdateLobbyPlayerEvent.create(panel.getType(), panel.getPlayerName(), panel.getAvatarIndex(), panel.getSleeveIndex(), panel.getTeam(), panel.isArchenemy(), panel.isReady(), panel.isDevMode(), panel.getAiOptions()); } public List getPlayerPanels() { diff --git a/forge-gui-mobile/src/forge/screens/constructed/PlayerPanel.java b/forge-gui-mobile/src/forge/screens/constructed/PlayerPanel.java index a2540d55f25..028a274db9a 100644 --- a/forge-gui-mobile/src/forge/screens/constructed/PlayerPanel.java +++ b/forge-gui-mobile/src/forge/screens/constructed/PlayerPanel.java @@ -59,7 +59,8 @@ public class PlayerPanel extends FContainer { private final FLabel nameRandomiser; private final FLabel avatarLabel = new FLabel.Builder().opaque(true).iconScaleFactor(0.99f).alphaComposite(1).iconInBackground(true).build(); - private int avatarIndex; + private final FLabel sleeveLabel = new FLabel.Builder().opaque(true).iconScaleFactor(0.99f).alphaComposite(1).iconInBackground(true).build(); + private int avatarIndex, sleeveIndex; final Localizer localizer = Localizer.getInstance(); private final FTextField txtPlayerName = new FTextField(localizer.getMessage("lblPlayerName")); @@ -98,6 +99,7 @@ public class PlayerPanel extends FContainer { setType(slot.getType()); setPlayerName(slot.getName()); setAvatarIndex(slot.getAvatarIndex()); + setSleeveIndex(slot.getSleeveIndex()); devModeSwitch = new FToggleSwitch(localizer.getMessage("lblNormal"), localizer.getMessage("lblDevMode")); devModeSwitch.setVisible(isNetworkHost()); @@ -189,6 +191,9 @@ public class PlayerPanel extends FContainer { createAvatar(); add(avatarLabel); + createSleeve(); + add(sleeveLabel); + createNameEditor(); add(newLabel(localizer.getMessage("lblName") + ":")); add(txtPlayerName); @@ -299,12 +304,16 @@ public class PlayerPanel extends FContainer { float y = PADDING; float fieldHeight = txtPlayerName.getHeight(); float avatarSize = 2 * fieldHeight + PADDING; + float sleeveSize = 2 * fieldHeight + PADDING; + float sleeveSizeW = (sleeveSize/4)*3; float dy = fieldHeight + PADDING; avatarLabel.setBounds(x, y, avatarSize, avatarSize); x += avatarSize + PADDING; + sleeveLabel.setBounds(x, y, sleeveSizeW, sleeveSize); + x += sleeveSizeW + PADDING; float w = width - x - fieldHeight - 2 * PADDING; - txtPlayerName.setBounds(x, y, w, fieldHeight); + txtPlayerName.setBounds(x, y, w, fieldHeight); //add space for card back x += w + PADDING; nameRandomiser.setBounds(x, y, fieldHeight, fieldHeight); @@ -312,8 +321,8 @@ public class PlayerPanel extends FContainer { humanAiSwitch.setSize(humanAiSwitch.getAutoSizeWidth(fieldHeight), fieldHeight); x = width - humanAiSwitch.getWidth() - PADDING; humanAiSwitch.setPosition(x, y); - w = x - avatarSize - 3 * PADDING; - x = avatarSize + 2 * PADDING; + w = x - (avatarSize+sleeveSizeW+PADDING) - 3 * PADDING; + x = (avatarSize+sleeveSizeW+PADDING) + 2 * PADDING; if (cbArchenemyTeam.isVisible()) { cbArchenemyTeam.setBounds(x, y, w, fieldHeight); } @@ -411,6 +420,7 @@ public class PlayerPanel extends FContainer { //update may edit in-case it changed as a result of the AI change setMayEdit(screen.getLobby().mayEdit(index)); setAvatarIndex(slot.getAvatarIndex()); + setSleeveIndex(slot.getSleeveIndex()); setPlayerName(slot.getName()); } } @@ -470,6 +480,7 @@ public class PlayerPanel extends FContainer { setAvatarIndex(result); if (index < 2) { + screen.updateAvatar(index, result); screen.updateAvatarPrefs(); } if (allowNetworking) { @@ -480,6 +491,26 @@ public class PlayerPanel extends FContainer { } }; + private FEventHandler sleeveCommand = new FEventHandler() { + @Override + public void handleEvent(FEvent e) { + SleevesSelector.show(getPlayerName(), sleeveIndex, screen.getUsedSleeves(), new Callback() { + @Override + public void run(Integer result) { + setSleeveIndex(result); + + if (index < 2) { + screen.updateSleeve(index, result); + screen.updateSleevePrefs(); + } + if (allowNetworking) { + screen.firePlayerChangeListener(index); + } + } + }); + } + }; + public void setDeckSelectorButtonText(String text) { btnDeck.setText(text); } @@ -664,6 +695,17 @@ public class PlayerPanel extends FContainer { avatarLabel.setCommand(avatarCommand); } + private void createSleeve() { + String[] currentPrefs = prefs.getPref(FPref.UI_SLEEVES).split(","); + if (index < currentPrefs.length) { + setSleeveIndex(Integer.parseInt(currentPrefs[index])); + } + else { + setSleeveIndex(SleevesSelector.getRandomSleeves(screen.getUsedSleeves())); + } + sleeveLabel.setCommand(sleeveCommand); + } + public void setAvatarIndex(int newAvatarIndex) { avatarIndex = newAvatarIndex; if (avatarIndex != -1) { @@ -674,10 +716,24 @@ public class PlayerPanel extends FContainer { } } + public void setSleeveIndex(int newSleeveIndex) { + sleeveIndex = newSleeveIndex; + if (sleeveIndex != -1) { + sleeveLabel.setIcon(new FTextureRegionImage(FSkin.getSleeves().get(newSleeveIndex))); + } + else { + sleeveLabel.setIcon(null); + } + } + public int getAvatarIndex() { return avatarIndex; } + public int getSleeveIndex() { + return sleeveIndex; + } + public void setPlayerName(String string) { txtPlayerName.setText(string); } @@ -759,6 +815,7 @@ public class PlayerPanel extends FContainer { if (mayEdit == mayEdit0) { return; } mayEdit = mayEdit0; avatarLabel.setEnabled(mayEdit); + sleeveLabel.setEnabled(mayEdit); txtPlayerName.setEnabled(mayEdit); nameRandomiser.setEnabled(mayEdit); humanAiSwitch.setEnabled(mayEdit); diff --git a/forge-gui-mobile/src/forge/screens/constructed/SleevesSelector.java b/forge-gui-mobile/src/forge/screens/constructed/SleevesSelector.java new file mode 100644 index 00000000000..523edea21b8 --- /dev/null +++ b/forge-gui-mobile/src/forge/screens/constructed/SleevesSelector.java @@ -0,0 +1,119 @@ +package forge.screens.constructed; + +import forge.Forge; +import forge.assets.FImage; +import forge.assets.FSkin; +import forge.assets.FSkinImage; +import forge.assets.FTextureRegionImage; +import forge.screens.FScreen; +import forge.toolbox.FDisplayObject; +import forge.toolbox.FEvent; +import forge.toolbox.FEvent.FEventHandler; +import forge.toolbox.FLabel; +import forge.toolbox.FScrollPane; +import forge.util.Callback; +import forge.util.MyRandom; +import forge.util.Utils; + +import java.util.List; +import java.util.Map; + +import com.badlogic.gdx.graphics.g2d.TextureRegion; +import com.badlogic.gdx.utils.Align; + +public class SleevesSelector extends FScreen { + public static int getRandomSleeves(List usedSleeves) { + int random = 0; + do { + random = MyRandom.getRandom().nextInt(FSkin.getSleeves().size()); + } while (usedSleeves.contains(random)); + return random; + } + + public static void show(final String playerName, final int currentIndex0, final List usedSleeves0, final Callback callback0) { + SleevesSelector selector = new SleevesSelector(playerName, currentIndex0, usedSleeves0, callback0); + Forge.openScreen(selector); + } + + private static final float PADDING = Utils.scale(5); + private static final int COLUMNS = 5; + + private final int currentIndex; + private final List usedSleeves; + private final Callback callback; + private final FScrollPane scroller = new FScrollPane() { + @Override + protected ScrollBounds layoutAndGetScrollBounds(float visibleWidth, float visibleHeight) { + int rowCount = 0; + float x = PADDING; + float y = PADDING; + float labelSize = (visibleWidth - (COLUMNS + 1) * PADDING) / COLUMNS; + for (FDisplayObject lbl : scroller.getChildren()) { + if (rowCount == COLUMNS) { //wrap to next line + x = PADDING; + y += labelSize + PADDING; + rowCount = 0; + } + lbl.setBounds(x, y, labelSize, labelSize); + x += labelSize + PADDING; + rowCount++; + } + return new ScrollBounds(visibleWidth, y + labelSize + PADDING); + } + }; + + private SleevesSelector(final String playerName, final int currentIndex0, final List usedSleeves0, final Callback callback0) { + super("Select Sleeves for " + playerName); + + currentIndex = currentIndex0; + usedSleeves = usedSleeves0; + callback = callback0; + + //add label for selecting random sleeves first + addSleevesLabel(FSkinImage.UNKNOWN, -1); + + //add label for currently selected sleeves next + final Map sleeveMap = FSkin.getSleeves(); + addSleevesLabel(new FTextureRegionImage(sleeveMap.get(currentIndex)), currentIndex); + + //add label for remaining sleeves + for (final Integer i : sleeveMap.keySet()) { + if (currentIndex != i) { + addSleevesLabel(new FTextureRegionImage(sleeveMap.get(i)), i); + } + } + + add(scroller); + } + + private void addSleevesLabel(final FImage img, final int index) { + final FLabel lbl = new FLabel.Builder().icon(img).iconScaleFactor(0.99f).align(Align.center) + .iconInBackground(true).selectable(true).selected(currentIndex == index) + .build(); + + if (index == -1) { + lbl.setCommand(new FEventHandler() { + @Override + public void handleEvent(FEvent e) { + callback.run(getRandomSleeves(usedSleeves)); + Forge.back(); + } + }); + } + else { + lbl.setCommand(new FEventHandler() { + @Override + public void handleEvent(FEvent e) { + callback.run(index); + Forge.back(); + } + }); + } + scroller.add(lbl); + } + + @Override + protected void doLayout(float startY, float width, float height) { + scroller.setBounds(0, startY, width, height - startY); + } +} diff --git a/forge-gui-mobile/src/forge/screens/match/MatchController.java b/forge-gui-mobile/src/forge/screens/match/MatchController.java index 8bc333ceb91..22255480344 100644 --- a/forge-gui-mobile/src/forge/screens/match/MatchController.java +++ b/forge-gui-mobile/src/forge/screens/match/MatchController.java @@ -7,6 +7,7 @@ import java.util.List; import java.util.Map; import java.util.Map.Entry; +import forge.assets.FSkinImage; import forge.util.Localizer; import org.apache.commons.lang3.StringUtils; @@ -68,6 +69,8 @@ public class MatchController extends AbstractGuiGame { private static final Map avatarImages = new HashMap<>(); + private static final Map sleeveImages = new HashMap<>(); + private static HostedMatch hostedMatch; private static MatchScreen view; @@ -100,6 +103,17 @@ public class MatchController extends AbstractGuiGame { return avatar; } + public static FImage getPlayerSleeve(final PlayerView p) { + if (p == null) + return FSkinImage.UNKNOWN; + final String lp = p.getLobbyPlayerName(); + FImage sleeve = sleeveImages.get(lp); + if (sleeve == null) { + sleeve = new FTextureRegionImage(FSkin.getSleeves().get(p.getSleeveIndex())); + } + return sleeve; + } + @Override public void refreshCardDetails(final Iterable cards) { //ensure cards appear in the correct row of the field diff --git a/forge-gui/res/puzzle/PS_ELD3.pzl b/forge-gui/res/puzzle/PS_ELD3.pzl new file mode 100644 index 00000000000..9ca10e7e032 --- /dev/null +++ b/forge-gui/res/puzzle/PS_ELD3.pzl @@ -0,0 +1,18 @@ +[metadata] +Name:Possibility Storm - Throne of Eldraine #03 +URL:http://www.possibilitystorm.com/wp-content/uploads/2019/10/134.-ELD3.jpg +Goal:Win +Turns:1 +Difficulty:Mythic +Description:Win this turn. Your opponent owns a Beanstalk Giant in exile. You have a Cryptic Caves in your graveyard. +[state] +humanlife=1 +ailife=7 +turn=1 +activeplayer=human +activephase=MAIN1 +humanhand=Giant Opportunity;Overgrown Tomb;Shepherd of the Flock;Overcome;Outmuscle +humangraveyard=Cryptic Caves +humanbattlefield=Wandermare;Kaya, Orzhov Usurper|Counters:LOYALTY=5;Vengeful Warchief;Trollbred Guardian;Jiang Yanggu, Wildcrafter|Counters:LOYALTY=1;Overgrown Tomb|NoETBTrigs;Overgrown Tomb|NoETBTrigs;Godless Shrine|NoETBTrigs;Godless Shrine|NoETBTrigs +aibattlefield=End-Raze Forerunners;Wardscale Crocodile +aiexile=Beanstalk Giant diff --git a/forge-gui/res/skins/default/sprite_sleeves.png b/forge-gui/res/skins/default/sprite_sleeves.png new file mode 100644 index 00000000000..d6e97d099b8 Binary files /dev/null and b/forge-gui/res/skins/default/sprite_sleeves.png differ diff --git a/forge-gui/res/skins/default/sprite_sleeves2.png b/forge-gui/res/skins/default/sprite_sleeves2.png new file mode 100644 index 00000000000..4916506f01e Binary files /dev/null and b/forge-gui/res/skins/default/sprite_sleeves2.png differ diff --git a/forge-gui/src/main/java/forge/interfaces/IGuiBase.java b/forge-gui/src/main/java/forge/interfaces/IGuiBase.java index 21802b2717d..4b137d323ef 100644 --- a/forge-gui/src/main/java/forge/interfaces/IGuiBase.java +++ b/forge-gui/src/main/java/forge/interfaces/IGuiBase.java @@ -46,6 +46,7 @@ public interface IGuiBase { boolean showBoxedProduct(String title, String message, List list); PaperCard chooseCard(String title, String message, List list); int getAvatarCount(); + int getSleevesCount(); void copyToClipboard(String text); void browseToUrl(String url) throws IOException, URISyntaxException; IAudioClip createAudioClip(String filename); diff --git a/forge-gui/src/main/java/forge/match/GameLobby.java b/forge-gui/src/main/java/forge/match/GameLobby.java index 6f9bfd78659..7e747c3e0e0 100644 --- a/forge-gui/src/main/java/forge/match/GameLobby.java +++ b/forge-gui/src/main/java/forge/match/GameLobby.java @@ -158,7 +158,7 @@ public abstract class GameLobby implements IHasGameType { public void addSlot() { final int newIndex = getNumberOfSlots(); final LobbySlotType type = allowNetworking ? LobbySlotType.OPEN : LobbySlotType.AI; - addSlot(new LobbySlot(type, null, newIndex, newIndex, false, !allowNetworking, Collections.emptySet())); + addSlot(new LobbySlot(type, null, newIndex, newIndex, newIndex, false, !allowNetworking, Collections.emptySet())); } protected final void addSlot(final LobbySlot slot) { if (slot == null) { @@ -198,6 +198,15 @@ public abstract class GameLobby implements IHasGameType { } return result; } + protected final static int[] localSleeveIndices() { + final String[] sSleeves = FModel.getPreferences().getPref(FPref.UI_SLEEVES).split(","); + final int[] result = new int[sSleeves.length]; + for (int i = 0; i < sSleeves.length; i++) { + final Integer val = Ints.tryParse(sSleeves[i]); + result[i] = val == null ? -1 : val.intValue(); + } + return result; + } public void removeSlot(final int index) { if (index < 0 || index >= data.slots.size()) { @@ -415,6 +424,7 @@ public abstract class GameLobby implements IHasGameType { final IGuiGame gui = getGui(data.slots.indexOf(slot)); final String name = slot.getName(); final int avatar = slot.getAvatarIndex(); + final int sleeve = slot.getSleeveIndex(); final boolean isArchenemy = slot.isArchenemy(); final int team = GameType.Archenemy.equals(currentGameType) && !isArchenemy ? 1 : slot.getTeam(); final Set aiOptions = slot.getAiOptions(); @@ -422,7 +432,7 @@ public abstract class GameLobby implements IHasGameType { final boolean isAI = slot.getType() == LobbySlotType.AI; final LobbyPlayer lobbyPlayer; if (isAI) { - lobbyPlayer = GamePlayerUtil.createAiPlayer(name, avatar, aiOptions); + lobbyPlayer = GamePlayerUtil.createAiPlayer(name, avatar, sleeve, aiOptions); } else { boolean setNameNow = false; @@ -430,7 +440,7 @@ public abstract class GameLobby implements IHasGameType { setNameNow = true; hasNameBeenSet = true; } - lobbyPlayer = GamePlayerUtil.getGuiPlayer(name, avatar, setNameNow); + lobbyPlayer = GamePlayerUtil.getGuiPlayer(name, avatar, sleeve, setNameNow); } Deck deck = slot.getDeck(); diff --git a/forge-gui/src/main/java/forge/match/HostedMatch.java b/forge-gui/src/main/java/forge/match/HostedMatch.java index 5d82270821c..84a4c43a494 100644 --- a/forge-gui/src/main/java/forge/match/HostedMatch.java +++ b/forge-gui/src/main/java/forge/match/HostedMatch.java @@ -158,6 +158,7 @@ public class HostedMatch { final FCollectionView players = game.getPlayers(); final String[] avatarIndices = FModel.getPreferences().getPref(FPref.UI_AVATARS).split(","); + final String[] sleeveIndices = FModel.getPreferences().getPref(FPref.UI_SLEEVES).split(","); final GameView gameView = getGameView(); humanCount = 0; @@ -175,6 +176,16 @@ public class HostedMatch { } } p.updateAvatar(); + //sleeve + p.getLobbyPlayer().setSleeveIndex(rp.getPlayer().getSleeveIndex()); + if (p.getLobbyPlayer().getSleeveIndex() == -1) { + if (iPlayer < sleeveIndices.length) { + p.getLobbyPlayer().setSleeveIndex(Integer.parseInt(sleeveIndices[iPlayer])); + } else { + p.getLobbyPlayer().setSleeveIndex(0); + } + } + p.updateSleeve(); if (p.getController() instanceof PlayerControllerHuman) { final PlayerControllerHuman humanController = (PlayerControllerHuman) p.getController(); diff --git a/forge-gui/src/main/java/forge/match/LobbySlot.java b/forge-gui/src/main/java/forge/match/LobbySlot.java index bd33cff83e9..e7c97666f53 100644 --- a/forge-gui/src/main/java/forge/match/LobbySlot.java +++ b/forge-gui/src/main/java/forge/match/LobbySlot.java @@ -15,6 +15,7 @@ public final class LobbySlot implements Serializable { private LobbySlotType type; private String name; private int avatarIndex; + private int sleeveIndex; private int team; private boolean isArchenemy; private boolean isReady; @@ -22,10 +23,11 @@ public final class LobbySlot implements Serializable { private Deck deck; private ImmutableSet aiOptions; - public LobbySlot(final LobbySlotType type, final String name, final int avatarIndex, final int team, final boolean isArchenemy, final boolean isReady, final Set aiOptions) { + public LobbySlot(final LobbySlotType type, final String name, final int avatarIndex, final int sleeveIndex, final int team, final boolean isArchenemy, final boolean isReady, final Set aiOptions) { this.type = type; this.name = name; this.avatarIndex = avatarIndex; + this.sleeveIndex = sleeveIndex; this.team = team; this.isArchenemy = isArchenemy; this.isReady = isReady; @@ -47,6 +49,10 @@ public final class LobbySlot implements Serializable { setAvatarIndex(data.getAvatarIndex()); changed = true; } + if (data.getSleeveIndex() != -1) { + setSleeveIndex(data.getSleeveIndex()); + changed = true; + } if (data.getTeam() != -1) { setTeam(data.getTeam()); changed = true; @@ -93,9 +99,15 @@ public final class LobbySlot implements Serializable { public int getAvatarIndex() { return avatarIndex; } + public int getSleeveIndex() { + return sleeveIndex; + } public void setAvatarIndex(final int avatarIndex) { this.avatarIndex = avatarIndex; } + public void setSleeveIndex(final int sleeveIndex) { + this.sleeveIndex = sleeveIndex; + } public int getTeam() { return team; diff --git a/forge-gui/src/main/java/forge/match/LocalLobby.java b/forge-gui/src/main/java/forge/match/LocalLobby.java index f8fa6f7a8e7..bb8c348f6a6 100644 --- a/forge-gui/src/main/java/forge/match/LocalLobby.java +++ b/forge-gui/src/main/java/forge/match/LocalLobby.java @@ -13,11 +13,12 @@ public final class LocalLobby extends GameLobby { final String humanName = localName(); final int[] avatarIndices = localAvatarIndices(); + final int[] sleeveIndices = localSleeveIndices(); - final LobbySlot slot0 = new LobbySlot(LobbySlotType.LOCAL, humanName, avatarIndices[0], 0, true, true, Collections.emptySet()); + final LobbySlot slot0 = new LobbySlot(LobbySlotType.LOCAL, humanName, avatarIndices[0], sleeveIndices[0],0, true, true, Collections.emptySet()); addSlot(slot0); - final LobbySlot slot1 = new LobbySlot(LobbySlotType.AI, null, avatarIndices[1], 1, false, true, Collections.emptySet()); + final LobbySlot slot1 = new LobbySlot(LobbySlotType.AI, null, avatarIndices[1], sleeveIndices[1],1, false, true, Collections.emptySet()); addSlot(slot1); } diff --git a/forge-gui/src/main/java/forge/net/OfflineLobby.java b/forge-gui/src/main/java/forge/net/OfflineLobby.java index e8827558e1a..392c8a880ca 100644 --- a/forge-gui/src/main/java/forge/net/OfflineLobby.java +++ b/forge-gui/src/main/java/forge/net/OfflineLobby.java @@ -14,11 +14,12 @@ public final class OfflineLobby extends GameLobby { final String humanName = localName(); final int[] avatarIndices = localAvatarIndices(); + final int[] sleeveIndices = localSleeveIndices(); - final LobbySlot slot0 = new LobbySlot(LobbySlotType.LOCAL, humanName, avatarIndices[0], 0, true, false, Collections.emptySet()); + final LobbySlot slot0 = new LobbySlot(LobbySlotType.LOCAL, humanName, avatarIndices[0], sleeveIndices[0], 0, true, false, Collections.emptySet()); addSlot(slot0); - final LobbySlot slot1 = new LobbySlot(LobbySlotType.OPEN, null, -1, -1, false, false, Collections.emptySet()); + final LobbySlot slot1 = new LobbySlot(LobbySlotType.OPEN, null, -1, -1,-1, false, false, Collections.emptySet()); addSlot(slot1); } diff --git a/forge-gui/src/main/java/forge/net/client/GameClientHandler.java b/forge-gui/src/main/java/forge/net/client/GameClientHandler.java index 30d977378a1..094123fe56a 100644 --- a/forge-gui/src/main/java/forge/net/client/GameClientHandler.java +++ b/forge-gui/src/main/java/forge/net/client/GameClientHandler.java @@ -198,7 +198,8 @@ final class GameClientHandler extends GameProtocolHandler { ); LobbyPlayer lobbyPlayer = new LobbyPlayerHuman( playerSlot.getName(), - playerSlot.getAvatarIndex() + playerSlot.getAvatarIndex(), + playerSlot.getSleeveIndex() ); player.setPlayer(lobbyPlayer); player.setTeamNumber(playerSlot.getTeam()); @@ -287,7 +288,7 @@ final class GameClientHandler extends GameProtocolHandler { @Override public void channelActive(final ChannelHandlerContext ctx) { // Don't use send() here, as this.channel is not yet set! - ctx.channel().writeAndFlush(new LoginEvent(FModel.getPreferences().getPref(FPref.PLAYER_NAME), Integer.parseInt(FModel.getPreferences().getPref(FPref.UI_AVATARS).split(",")[0]))); + ctx.channel().writeAndFlush(new LoginEvent(FModel.getPreferences().getPref(FPref.PLAYER_NAME), Integer.parseInt(FModel.getPreferences().getPref(FPref.UI_AVATARS).split(",")[0]), Integer.parseInt(FModel.getPreferences().getPref(FPref.UI_SLEEVES).split(",")[0]))); } } \ No newline at end of file diff --git a/forge-gui/src/main/java/forge/net/event/LoginEvent.java b/forge-gui/src/main/java/forge/net/event/LoginEvent.java index 92d5b016b67..170750751a9 100644 --- a/forge-gui/src/main/java/forge/net/event/LoginEvent.java +++ b/forge-gui/src/main/java/forge/net/event/LoginEvent.java @@ -6,10 +6,11 @@ public class LoginEvent implements NetEvent { private static final long serialVersionUID = -8865183377417377938L; private final String username; - private final int avatarIndex; - public LoginEvent(final String username, final int avatarIndex) { + private final int avatarIndex, sleeveIndex; + public LoginEvent(final String username, final int avatarIndex, final int sleeveIndex) { this.username = username; this.avatarIndex = avatarIndex; + this.sleeveIndex = sleeveIndex; } @Override @@ -23,4 +24,8 @@ public class LoginEvent implements NetEvent { public int getAvatarIndex() { return avatarIndex; } + + public int getSleeveIndex() { + return sleeveIndex; + } } diff --git a/forge-gui/src/main/java/forge/net/event/UpdateLobbyPlayerEvent.java b/forge-gui/src/main/java/forge/net/event/UpdateLobbyPlayerEvent.java index 7640472ba6d..7fae4077b10 100644 --- a/forge-gui/src/main/java/forge/net/event/UpdateLobbyPlayerEvent.java +++ b/forge-gui/src/main/java/forge/net/event/UpdateLobbyPlayerEvent.java @@ -16,6 +16,7 @@ public final class UpdateLobbyPlayerEvent implements NetEvent { private LobbySlotType type = null; private String name = null; private int avatarIndex = -1; + private int sleeveIndex = -1; private int team = -1; private Boolean isArchenemy = null; private Boolean isReady = null; @@ -26,11 +27,11 @@ public final class UpdateLobbyPlayerEvent implements NetEvent { private Set aiOptions = null; - public static UpdateLobbyPlayerEvent create(final LobbySlotType type, final String name, final int avatarIndex, final int team, final boolean isArchenemy, final boolean isReady, final Set aiOptions) { - return new UpdateLobbyPlayerEvent(type, name, avatarIndex, team, isArchenemy, isReady, aiOptions); + public static UpdateLobbyPlayerEvent create(final LobbySlotType type, final String name, final int avatarIndex, final int sleeveIndex, final int team, final boolean isArchenemy, final boolean isReady, final Set aiOptions) { + return new UpdateLobbyPlayerEvent(type, name, avatarIndex, sleeveIndex, team, isArchenemy, isReady, aiOptions); } - public static UpdateLobbyPlayerEvent create(final LobbySlotType type, final String name, final int avatarIndex, final int team, final boolean isArchenemy, final boolean isReady, final boolean isDevMode, final Set aiOptions) { - return new UpdateLobbyPlayerEvent(type, name, avatarIndex, team, isArchenemy, isReady, isDevMode, aiOptions); + public static UpdateLobbyPlayerEvent create(final LobbySlotType type, final String name, final int avatarIndex, final int sleeveIndex, final int team, final boolean isArchenemy, final boolean isReady, final boolean isDevMode, final Set aiOptions) { + return new UpdateLobbyPlayerEvent(type, name, avatarIndex, sleeveIndex, team, isArchenemy, isReady, isDevMode, aiOptions); } public static UpdateLobbyPlayerEvent deckUpdate(final Deck deck) { return new UpdateLobbyPlayerEvent(deck); @@ -46,6 +47,19 @@ public final class UpdateLobbyPlayerEvent implements NetEvent { this.name = name; } + public static UpdateLobbyPlayerEvent avatarUpdate(final int index) { + return new UpdateLobbyPlayerEvent(index, true); + } + public static UpdateLobbyPlayerEvent sleeveUpdate(final int index) { + return new UpdateLobbyPlayerEvent(index, false); + } + private UpdateLobbyPlayerEvent(int index, boolean avatar) { + if (avatar) + this.avatarIndex = index; + else + this.sleeveIndex = index; + } + private UpdateLobbyPlayerEvent(final Deck deck) { this.deck = deck; } @@ -59,6 +73,7 @@ public final class UpdateLobbyPlayerEvent implements NetEvent { final LobbySlotType type, final String name, final int avatarIndex, + final int sleeveIndex, final int team, final boolean isArchenemy, final boolean isReady, @@ -66,6 +81,7 @@ public final class UpdateLobbyPlayerEvent implements NetEvent { this.type = type; this.name = name; this.avatarIndex = avatarIndex; + this.sleeveIndex = sleeveIndex; this.team = team; this.isArchenemy = isArchenemy; this.isReady = isReady; @@ -76,6 +92,7 @@ public final class UpdateLobbyPlayerEvent implements NetEvent { final LobbySlotType type, final String name, final int avatarIndex, + final int sleeveIndex, final int team, final boolean isArchenemy, final boolean isReady, @@ -84,6 +101,7 @@ public final class UpdateLobbyPlayerEvent implements NetEvent { this.type = type; this.name = name; this.avatarIndex = avatarIndex; + this.sleeveIndex = sleeveIndex; this.team = team; this.isArchenemy = isArchenemy; this.isReady = isReady; @@ -104,6 +122,9 @@ public final class UpdateLobbyPlayerEvent implements NetEvent { public int getAvatarIndex() { return avatarIndex; } + public int getSleeveIndex() { + return sleeveIndex; + } public int getTeam() { return team; } diff --git a/forge-gui/src/main/java/forge/net/server/FServerManager.java b/forge-gui/src/main/java/forge/net/server/FServerManager.java index 4a17201fd69..48cfe582ec6 100644 --- a/forge-gui/src/main/java/forge/net/server/FServerManager.java +++ b/forge-gui/src/main/java/forge/net/server/FServerManager.java @@ -329,7 +329,7 @@ public final class FServerManager { final RemoteClient client = clients.get(ctx.channel()); if (msg instanceof LoginEvent) { final LoginEvent event = (LoginEvent) msg; - final int index = localLobby.connectPlayer(event.getUsername(), event.getAvatarIndex()); + final int index = localLobby.connectPlayer(event.getUsername(), event.getAvatarIndex(), event.getSleeveIndex()); if (index == -1) { ctx.close(); } else { diff --git a/forge-gui/src/main/java/forge/net/server/ServerGameLobby.java b/forge-gui/src/main/java/forge/net/server/ServerGameLobby.java index 9fd87b8b132..255ad807c63 100644 --- a/forge-gui/src/main/java/forge/net/server/ServerGameLobby.java +++ b/forge-gui/src/main/java/forge/net/server/ServerGameLobby.java @@ -13,25 +13,26 @@ public final class ServerGameLobby extends GameLobby { public ServerGameLobby() { super(true); - addSlot(new LobbySlot(LobbySlotType.LOCAL, localName(), localAvatarIndices()[0], 0, true, false, Collections.emptySet())); - addSlot(new LobbySlot(LobbySlotType.OPEN, null, -1, 1, false, false, Collections.emptySet())); + addSlot(new LobbySlot(LobbySlotType.LOCAL, localName(), localAvatarIndices()[0], localSleeveIndices()[0],0, true, false, Collections.emptySet())); + addSlot(new LobbySlot(LobbySlotType.OPEN, null, -1, -1, 1, false, false, Collections.emptySet())); } - public int connectPlayer(final String name, final int avatarIndex) { + public int connectPlayer(final String name, final int avatarIndex, final int sleeveIndex) { final int nSlots = getNumberOfSlots(); for (int index = 0; index < nSlots; index++) { final LobbySlot slot = getSlot(index); if (slot.getType() == LobbySlotType.OPEN) { - connectPlayer(name, avatarIndex, slot); + connectPlayer(name, avatarIndex, sleeveIndex, slot); return index; } } return -1; } - private void connectPlayer(final String name, final int avatarIndex, final LobbySlot slot) { + private void connectPlayer(final String name, final int avatarIndex, final int sleeveIndex, final LobbySlot slot) { slot.setType(LobbySlotType.REMOTE); slot.setName(name); slot.setAvatarIndex(avatarIndex); + slot.setSleeveIndex(sleeveIndex); updateView(false); } public void disconnectPlayer(final int index) { diff --git a/forge-gui/src/main/java/forge/planarconquest/ConquestController.java b/forge-gui/src/main/java/forge/planarconquest/ConquestController.java index 41dba7860ac..19d10ebd25c 100644 --- a/forge-gui/src/main/java/forge/planarconquest/ConquestController.java +++ b/forge-gui/src/main/java/forge/planarconquest/ConquestController.java @@ -127,7 +127,7 @@ public class ConquestController { starter.add(humanStart.setPlayer(humanPlayer)); final IGuiGame gui = GuiBase.getInterface().getNewGuiGame(); - final LobbyPlayer aiPlayer = GamePlayerUtil.createAiPlayer(aiPlayerName, -1); + final LobbyPlayer aiPlayer = GamePlayerUtil.createAiPlayer(aiPlayerName, -1, -1); battle.setOpponentAvatar(aiPlayer, gui); starter.add(aiStart.setPlayer(aiPlayer)); diff --git a/forge-gui/src/main/java/forge/player/GamePlayerUtil.java b/forge-gui/src/main/java/forge/player/GamePlayerUtil.java index a7a93d85006..ee63047e9bd 100644 --- a/forge-gui/src/main/java/forge/player/GamePlayerUtil.java +++ b/forge-gui/src/main/java/forge/player/GamePlayerUtil.java @@ -23,7 +23,7 @@ public final class GamePlayerUtil { public static final LobbyPlayer getGuiPlayer() { return guiPlayer; } - public static final LobbyPlayer getGuiPlayer(final String name, final int avatarIndex, final boolean writePref) { + public static final LobbyPlayer getGuiPlayer(final String name, final int avatarIndex, final int sleeveIndex, final boolean writePref) { if (writePref) { if (!name.equals(guiPlayer.getName())) { guiPlayer.setName(name); @@ -33,7 +33,7 @@ public final class GamePlayerUtil { return guiPlayer; } //use separate LobbyPlayerHuman instance for human players beyond first - return new LobbyPlayerHuman(name, avatarIndex); + return new LobbyPlayerHuman(name, avatarIndex, sleeveIndex); } public static final LobbyPlayer getQuestPlayer() { @@ -45,19 +45,25 @@ public final class GamePlayerUtil { } public final static LobbyPlayer createAiPlayer(final String name) { final int avatarCount = GuiBase.getInterface().getAvatarCount(); - return createAiPlayer(name, avatarCount == 0 ? 0 : MyRandom.getRandom().nextInt(avatarCount)); + final int sleeveCount = GuiBase.getInterface().getSleevesCount(); + return createAiPlayer(name, avatarCount == 0 ? 0 : MyRandom.getRandom().nextInt(avatarCount), sleeveCount == 0 ? 0 : MyRandom.getRandom().nextInt(sleeveCount)); } public final static LobbyPlayer createAiPlayer(final String name, final String profileOverride) { final int avatarCount = GuiBase.getInterface().getAvatarCount(); - return createAiPlayer(name, avatarCount == 0 ? 0 : MyRandom.getRandom().nextInt(avatarCount), null, profileOverride); + final int sleeveCount = GuiBase.getInterface().getSleevesCount(); + return createAiPlayer(name, avatarCount == 0 ? 0 : MyRandom.getRandom().nextInt(avatarCount), sleeveCount == 0 ? 0 : MyRandom.getRandom().nextInt(sleeveCount), null, profileOverride); } public final static LobbyPlayer createAiPlayer(final String name, final int avatarIndex) { - return createAiPlayer(name, avatarIndex, null, ""); + final int sleeveCount = GuiBase.getInterface().getSleevesCount(); + return createAiPlayer(name, avatarIndex, sleeveCount == 0 ? 0 : MyRandom.getRandom().nextInt(sleeveCount), null, ""); } - public final static LobbyPlayer createAiPlayer(final String name, final int avatarIndex, final Set options) { - return createAiPlayer(name, avatarIndex, options, ""); + public final static LobbyPlayer createAiPlayer(final String name, final int avatarIndex, final int sleeveIndex) { + return createAiPlayer(name, avatarIndex, sleeveIndex, null, ""); } - public final static LobbyPlayer createAiPlayer(final String name, final int avatarIndex, final Set options, final String profileOverride) { + public final static LobbyPlayer createAiPlayer(final String name, final int avatarIndex, final int sleeveIndex, final Set options) { + return createAiPlayer(name, avatarIndex, sleeveIndex, options, ""); + } + public final static LobbyPlayer createAiPlayer(final String name, final int avatarIndex, final int sleeveIndex, final Set options, final String profileOverride) { final LobbyPlayerAi player = new LobbyPlayerAi(name, options); // TODO: implement specific AI profiles for quest mode. @@ -87,6 +93,7 @@ public final class GamePlayerUtil { player.setAiProfile(profile); player.setAvatarIndex(avatarIndex); + player.setSleeveIndex(sleeveIndex); return player; } diff --git a/forge-gui/src/main/java/forge/player/LobbyPlayerHuman.java b/forge-gui/src/main/java/forge/player/LobbyPlayerHuman.java index 04d8a75a5c8..e5882646851 100644 --- a/forge-gui/src/main/java/forge/player/LobbyPlayerHuman.java +++ b/forge-gui/src/main/java/forge/player/LobbyPlayerHuman.java @@ -9,11 +9,12 @@ import forge.util.GuiDisplayUtil; public class LobbyPlayerHuman extends LobbyPlayer implements IGameEntitiesFactory { public LobbyPlayerHuman(final String name) { - this(name, -1); + this(name, -1, -1); } - public LobbyPlayerHuman(final String name, final int avatarIndex) { + public LobbyPlayerHuman(final String name, final int avatarIndex, final int sleeveIndex) { super(name); setAvatarIndex(avatarIndex); + setSleeveIndex(sleeveIndex); } @Override diff --git a/forge-gui/src/main/java/forge/properties/ForgeConstants.java b/forge-gui/src/main/java/forge/properties/ForgeConstants.java index 29f0c9aafd7..42d07add4e3 100644 --- a/forge-gui/src/main/java/forge/properties/ForgeConstants.java +++ b/forge-gui/src/main/java/forge/properties/ForgeConstants.java @@ -97,6 +97,8 @@ public final class ForgeConstants { public static final String SPRITE_BORDER_FILE = "sprite_border.png"; public static final String SPRITE_MANAICONS_FILE = "sprite_manaicons.png"; public static final String SPRITE_AVATARS_FILE = "sprite_avatars.png"; + public static final String SPRITE_SLEEVES_FILE = "sprite_sleeves.png"; + public static final String SPRITE_SLEEVES2_FILE = "sprite_sleeves2.png"; public static final String SPRITE_FAVICONS_FILE = "sprite_favicons.png"; public static final String SPRITE_PLANAR_CONQUEST_FILE = "sprite_planar_conquest.png"; public static final String FONT_FILE = "font1.ttf"; diff --git a/forge-gui/src/main/java/forge/properties/ForgePreferences.java b/forge-gui/src/main/java/forge/properties/ForgePreferences.java index 11d6627965a..941ac2a1ed0 100644 --- a/forge-gui/src/main/java/forge/properties/ForgePreferences.java +++ b/forge-gui/src/main/java/forge/properties/ForgePreferences.java @@ -73,6 +73,7 @@ public class ForgePreferences extends PreferencesStore { UI_RANDOM_FOIL ("false"), UI_ENABLE_AI_CHEATS ("false"), UI_AVATARS ("0,1"), + UI_SLEEVES ("0,1"), UI_SHOW_CARD_OVERLAYS ("true"), UI_OVERLAY_CARD_NAME ("true"), UI_OVERLAY_CARD_POWER ("true"),