This commit is contained in:
Alessandro Coli
2019-10-31 14:10:41 +01:00
39 changed files with 774 additions and 85 deletions

View File

@@ -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;

View File

@@ -2430,6 +2430,7 @@ public class Player extends GameEntity implements Comparable<Player> {
controllerCreator = ctrlr;
controller = ctrlr;
updateAvatar();
updateSleeve();
view.updateIsAI(this);
view.updateLobbyPlayerName(this);
}
@@ -2439,6 +2440,10 @@ public class Player extends GameEntity implements Comparable<Player> {
view.updateAvatarCardImageKey(this);
}
public void updateSleeve() {
view.updateSleeveIndex(this);
}
/**
* Run a procedure using a different controller
*/

View File

@@ -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);

View File

@@ -124,7 +124,7 @@ public class StaticAbilityCantTarget {
}
}
return true;
return common(st, spellAbility);
}
protected static boolean common(final StaticAbility st, final SpellAbility spellAbility) {

View File

@@ -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),

View File

@@ -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);

View File

@@ -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<Integer> 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();
}

View File

@@ -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<Integer> getUsedSleeves() {
final List<Integer> usedSleeves = Lists.newArrayListWithCapacity(MAX_PLAYERS);
for (final PlayerPanel pp : playerPanels) {
usedSleeves.add(pp.getSleeveIndex());
}
return usedSleeves;
}
private static final ImmutableList<String> genderOptions = ImmutableList.of("Male", "Female", "Any"),
typeOptions = ImmutableList.of("Fantasy", "Generic", "Any");

View File

@@ -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<FLabel> selectables = new ArrayList<>();
private final Map<Integer, FSkin.SkinImage> sleeveMap = FSkin.getSleeves();
public SleeveSelector(final String playerName, final int currentIndex, final Collection<Integer> 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<FLabel> getSelectables() {
return this.selectables;
}
}

View File

@@ -859,6 +859,7 @@ public class FSkin {
}
private static Map<Integer, SkinImage> avatars;
private static Map<Integer, SkinImage> sleeves;
private static Map<Integer, Font> 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<Integer, SkinImage> 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];

View File

@@ -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

View File

@@ -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<FSkinProp, FSkinImage> images = new HashMap<>();
private static final Map<Integer, TextureRegion> avatars = new HashMap<>();
private static final Map<Integer, TextureRegion> sleeves = new HashMap<>();
private static final Map<Integer, TextureRegion> borders = new HashMap<>();
private static List<String> allSkins;
private static Array<String> 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<String> skinDirectoryNames = getSkinDirectoryNames();
allSkins = new Array<>();
final Array<String> 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<String, Texture> 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<String> getSkinDirectoryNames() {
final List<String> mySkins = new ArrayList<>();
public static Array<String> getSkinDirectoryNames() {
final Array<String> 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<Integer, TextureRegion> getSleeves() {
return sleeves;
}
public static Map<Integer, TextureRegion> getBorders() {
return borders;
}
public static boolean isLoaded() { return loaded; }
}

View File

@@ -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;

View File

@@ -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) {

View File

@@ -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);
}
}
}

View File

@@ -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<Integer> usedAvatars;

View File

@@ -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<Integer> getUsedSleeves() {
List<Integer> 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<String> getPlayerNames() {
List<String> 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<PlayerPanel> getPlayerPanels() {

View File

@@ -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<Integer>() {
@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);

View File

@@ -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<Integer> 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<Integer> usedSleeves0, final Callback<Integer> 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<Integer> usedSleeves;
private final Callback<Integer> 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<Integer> usedSleeves0, final Callback<Integer> 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<Integer, TextureRegion> 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);
}
}

View File

@@ -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<String, FImage> avatarImages = new HashMap<>();
private static final Map<String, FImage> 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<CardView> cards) {
//ensure cards appear in the correct row of the field

View File

@@ -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

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 697 KiB

View File

@@ -46,6 +46,7 @@ public interface IGuiBase {
boolean showBoxedProduct(String title, String message, List<PaperCard> list);
PaperCard chooseCard(String title, String message, List<PaperCard> list);
int getAvatarCount();
int getSleevesCount();
void copyToClipboard(String text);
void browseToUrl(String url) throws IOException, URISyntaxException;
IAudioClip createAudioClip(String filename);

View File

@@ -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<AIOption> 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();

View File

@@ -158,6 +158,7 @@ public class HostedMatch {
final FCollectionView<Player> 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();

View File

@@ -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<AIOption> aiOptions;
public LobbySlot(final LobbySlotType type, final String name, final int avatarIndex, final int team, final boolean isArchenemy, final boolean isReady, final Set<AIOption> 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<AIOption> 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;

View File

@@ -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);
}

View File

@@ -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);
}

View File

@@ -198,7 +198,8 @@ final class GameClientHandler extends GameProtocolHandler<IGuiGame> {
);
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<IGuiGame> {
@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])));
}
}

View File

@@ -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;
}
}

View File

@@ -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<AIOption> 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<AIOption> 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<AIOption> 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<AIOption> 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<AIOption> 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;
}

View File

@@ -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 {

View File

@@ -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) {

View File

@@ -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));

View File

@@ -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<AIOption> 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<AIOption> options, final String profileOverride) {
public final static LobbyPlayer createAiPlayer(final String name, final int avatarIndex, final int sleeveIndex, final Set<AIOption> options) {
return createAiPlayer(name, avatarIndex, sleeveIndex, options, "");
}
public final static LobbyPlayer createAiPlayer(final String name, final int avatarIndex, final int sleeveIndex, final Set<AIOption> 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;
}

View File

@@ -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

View File

@@ -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";

View File

@@ -73,6 +73,7 @@ public class ForgePreferences extends PreferencesStore<ForgePreferences.FPref> {
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"),