Add counters to mobile Forge and adjust desktop counters

This commit is contained in:
Krazy
2017-06-24 21:49:36 +00:00
parent 4a7f967541
commit 5a2d45ba28
11 changed files with 330 additions and 80 deletions

2
.gitattributes vendored
View File

@@ -1174,7 +1174,6 @@ forge-gui-desktop/src/main/java/forge/view/arcane/util/CardPanelMouseListener.ja
forge-gui-desktop/src/main/java/forge/view/arcane/util/OutlinedLabel.java -text forge-gui-desktop/src/main/java/forge/view/arcane/util/OutlinedLabel.java -text
forge-gui-desktop/src/main/java/forge/view/arcane/util/package-info.java -text forge-gui-desktop/src/main/java/forge/view/arcane/util/package-info.java -text
forge-gui-desktop/src/main/java/forge/view/package-info.java -text forge-gui-desktop/src/main/java/forge/view/package-info.java -text
forge-gui-desktop/src/main/resources/Roboto-Bold.ttf -text
forge-gui-desktop/src/test/java/forge/BoosterDraft1Test.java -text forge-gui-desktop/src/test/java/forge/BoosterDraft1Test.java -text
forge-gui-desktop/src/test/java/forge/BoosterDraftTest.java -text forge-gui-desktop/src/test/java/forge/BoosterDraftTest.java -text
forge-gui-desktop/src/test/java/forge/CardRankerTest.java -text forge-gui-desktop/src/test/java/forge/CardRankerTest.java -text
@@ -19084,6 +19083,7 @@ forge-gui/res/editions/Worldwake.txt -text
forge-gui/res/editions/Zendikar[!!-~]Expeditions.txt -text forge-gui/res/editions/Zendikar[!!-~]Expeditions.txt -text
forge-gui/res/editions/Zendikar.txt -text forge-gui/res/editions/Zendikar.txt -text
forge-gui/res/effects/lightning.gif -text forge-gui/res/effects/lightning.gif -text
forge-gui/res/fonts/Roboto-Bold.ttf -text
forge-gui/res/howto.txt svneol=native#text/plain forge-gui/res/howto.txt svneol=native#text/plain
forge-gui/res/languages/en-US.properties -text forge-gui/res/languages/en-US.properties -text
forge-gui/res/licenses/java-yield-license.txt svneol=native#text/plain forge-gui/res/licenses/java-yield-license.txt svneol=native#text/plain

View File

@@ -195,6 +195,7 @@ public enum CSubmenuPreferences implements ICDoc {
initializeColorIdentityCombobox(); initializeColorIdentityCombobox();
initializeAutoYieldModeComboBox(); initializeAutoYieldModeComboBox();
initializeCounterDisplayTypeComboBox(); initializeCounterDisplayTypeComboBox();
initializeCounterDisplayLocationComboBox();
initializePlayerNameButton(); initializePlayerNameButton();
} }
@@ -360,6 +361,25 @@ public enum CSubmenuPreferences implements ICDoc {
} }
private void initializeCounterDisplayLocationComboBox() {
final String[] elements = new String[ForgeConstants.CounterDisplayLocation.values().length];
ForgeConstants.CounterDisplayLocation[] values = ForgeConstants.CounterDisplayLocation.values();
for (int i = 0; i < values.length; i++) {
elements[i] = values[i].getName();
}
final FPref userSetting = FPref.UI_CARD_COUNTER_DISPLAY_LOCATION;
final FComboBoxPanel<String> panel = this.view.getCounterDisplayLocationComboBoxPanel();
final FComboBox<String> comboBox = createComboBox(elements, userSetting);
final String selectedItem = this.prefs.getPref(userSetting);
panel.setComboBox(comboBox, selectedItem);
}
private <E> FComboBox<E> createComboBox(final E[] items, final ForgePreferences.FPref setting) { private <E> FComboBox<E> createComboBox(final E[] items, final ForgePreferences.FPref setting) {
final FComboBox<E> comboBox = new FComboBox<>(items); final FComboBox<E> comboBox = new FComboBox<>(items);
addComboBoxListener(comboBox, setting); addComboBoxListener(comboBox, setting);

View File

@@ -103,6 +103,7 @@ public enum VSubmenuPreferences implements IVSubmenu<CSubmenuPreferences> {
private final FComboBoxPanel<String> cbpDisplayCurrentCardColors = new FComboBoxPanel<>("Show Detailed Card Color:"); private final FComboBoxPanel<String> cbpDisplayCurrentCardColors = new FComboBoxPanel<>("Show Detailed Card Color:");
private final FComboBoxPanel<String> cbpAutoYieldMode = new FComboBoxPanel<>("Auto-Yield:"); private final FComboBoxPanel<String> cbpAutoYieldMode = new FComboBoxPanel<>("Auto-Yield:");
private final FComboBoxPanel<String> cbpCounterDisplayType = new FComboBoxPanel<>("Counter Display Type:"); private final FComboBoxPanel<String> cbpCounterDisplayType = new FComboBoxPanel<>("Counter Display Type:");
private final FComboBoxPanel<String> cbpCounterDisplayLocation = new FComboBoxPanel<>("Counter Display Location:");
/** /**
* Constructor. * Constructor.
@@ -280,6 +281,9 @@ public enum VSubmenuPreferences implements IVSubmenu<CSubmenuPreferences> {
pnlPrefs.add(cbpCounterDisplayType, comboBoxConstraints); pnlPrefs.add(cbpCounterDisplayType, comboBoxConstraints);
pnlPrefs.add(new NoteLabel("Selects the style of the in-game counter display for cards. Text-based is a new tab-like display on the cards. Image-based is the old counter image. Hybrid displays both at once."), descriptionConstraints); pnlPrefs.add(new NoteLabel("Selects the style of the in-game counter display for cards. Text-based is a new tab-like display on the cards. Image-based is the old counter image. Hybrid displays both at once."), descriptionConstraints);
pnlPrefs.add(cbpCounterDisplayLocation, comboBoxConstraints);
pnlPrefs.add(new NoteLabel("Determines where to position the text-based counters on the card: close to the top or close to the bottom."), descriptionConstraints);
pnlPrefs.add(cbpDisplayCurrentCardColors, comboBoxConstraints); pnlPrefs.add(cbpDisplayCurrentCardColors, comboBoxConstraints);
pnlPrefs.add(new NoteLabel("Displays the breakdown of the current color of cards in the card detail information panel."), descriptionConstraints); pnlPrefs.add(new NoteLabel("Displays the breakdown of the current color of cards in the card detail information panel."), descriptionConstraints);
@@ -593,6 +597,10 @@ public enum VSubmenuPreferences implements IVSubmenu<CSubmenuPreferences> {
return cbpCounterDisplayType; return cbpCounterDisplayType;
} }
public FComboBoxPanel<String> getCounterDisplayLocationComboBoxPanel() {
return cbpCounterDisplayLocation;
}
/** @return {@link javax.swing.JCheckBox} */ /** @return {@link javax.swing.JCheckBox} */
public JCheckBox getCbEnforceDeckLegality() { public JCheckBox getCbEnforceDeckLegality() {
return cbEnforceDeckLegality; return cbEnforceDeckLegality;

View File

@@ -29,6 +29,7 @@ import forge.game.card.CounterType;
import forge.gui.CardContainer; import forge.gui.CardContainer;
import forge.item.PaperCard; import forge.item.PaperCard;
import forge.model.FModel; import forge.model.FModel;
import forge.properties.ForgeConstants;
import forge.properties.ForgeConstants.CounterDisplayType; import forge.properties.ForgeConstants.CounterDisplayType;
import forge.properties.ForgePreferences.FPref; import forge.properties.ForgePreferences.FPref;
import forge.screens.match.CMatchUI; import forge.screens.match.CMatchUI;
@@ -45,6 +46,7 @@ import java.awt.font.TextAttribute;
import java.awt.geom.RoundRectangle2D; import java.awt.geom.RoundRectangle2D;
import java.awt.image.BufferedImage; import java.awt.image.BufferedImage;
import java.io.IOException; import java.io.IOException;
import java.nio.file.Paths;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
@@ -99,7 +101,7 @@ public class CardPanel extends SkinnedPanel implements CardContainer, IDisposabl
try { try {
Font roboto = Font.createFont(Font.TRUETYPE_FONT, CardPanel.class.getClassLoader().getResourceAsStream("Roboto-Bold.ttf")); Font roboto = Font.createFont(Font.TRUETYPE_FONT, Paths.get(ForgeConstants.COMMON_FONTS_DIR, "Roboto-Bold.ttf").toFile());
GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment(); GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
ge.registerFont(roboto); ge.registerFont(roboto);
@@ -108,7 +110,7 @@ public class CardPanel extends SkinnedPanel implements CardContainer, IDisposabl
attributes.put(TextAttribute.FAMILY, "Roboto Bold"); attributes.put(TextAttribute.FAMILY, "Roboto Bold");
attributes.put(TextAttribute.WEIGHT, TextAttribute.WEIGHT_BOLD); attributes.put(TextAttribute.WEIGHT, TextAttribute.WEIGHT_BOLD);
attributes.put(TextAttribute.SIZE, 10); attributes.put(TextAttribute.SIZE, 11);
attributes.put(TextAttribute.KERNING, TextAttribute.KERNING_ON); attributes.put(TextAttribute.KERNING, TextAttribute.KERNING_ON);
smallCounterFont = Font.getFont(attributes); smallCounterFont = Font.getFont(attributes);
@@ -437,7 +439,7 @@ public class CardPanel extends SkinnedPanel implements CardContainer, IDisposabl
} }
if (card.getCounters() != null) { if (card.getCounters() != null && !card.getCounters().isEmpty()) {
switch (CounterDisplayType.from(FModel.getPreferences().getPref(FPref.UI_CARD_COUNTER_DISPLAY_TYPE))) { switch (CounterDisplayType.from(FModel.getPreferences().getPref(FPref.UI_CARD_COUNTER_DISPLAY_TYPE))) {
case OLD_WHEN_SMALL: case OLD_WHEN_SMALL:
@@ -517,7 +519,13 @@ public class CardPanel extends SkinnedPanel implements CardContainer, IDisposabl
final int numberOfCounters = counterEntry.getValue(); final int numberOfCounters = counterEntry.getValue();
final int counterBoxRealWidth = counterBoxBaseWidth + largeFontMetrics.stringWidth(String.valueOf(numberOfCounters)); final int counterBoxRealWidth = counterBoxBaseWidth + largeFontMetrics.stringWidth(String.valueOf(numberOfCounters));
final int counterYOffset = cardYOffset + spaceFromTopOfCard - counterBoxHeight + currentCounter++ * (counterBoxHeight + counterBoxSpacing); final int counterYOffset;
if (ForgeConstants.CounterDisplayLocation.from(FModel.getPreferences().getPref(FPref.UI_CARD_COUNTER_DISPLAY_LOCATION)) == ForgeConstants.CounterDisplayLocation.TOP) {
counterYOffset = cardYOffset + spaceFromTopOfCard - counterBoxHeight + currentCounter++ * (counterBoxHeight + counterBoxSpacing);
} else {
counterYOffset = cardYOffset + cardHeight - spaceFromTopOfCard / 2 - counterBoxHeight + currentCounter++ * (counterBoxHeight + counterBoxSpacing);
}
if (isSelected) { if (isSelected) {
g.setColor(new Color(0, 0, 0, 255)); g.setColor(new Color(0, 0, 0, 255));
@@ -537,7 +545,8 @@ public class CardPanel extends SkinnedPanel implements CardContainer, IDisposabl
} }
Rectangle nameBounds = counterArea.getBounds(); Rectangle nameBounds = counterArea.getBounds();
nameBounds.x += 12; nameBounds.x += 8;
nameBounds.y -= 1;
nameBounds.width = 43; nameBounds.width = 43;
drawVerticallyCenteredString(g, counter.getCounterOnCardDisplayName(), nameBounds, smallCounterFont, smallFontMetrics); drawVerticallyCenteredString(g, counter.getCounterOnCardDisplayName(), nameBounds, smallCounterFont, smallFontMetrics);

View File

@@ -1,15 +1,13 @@
package forge; package forge;
import java.util.Stack;
import com.badlogic.gdx.Gdx; import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.Color; import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.GL20; import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.Texture; import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.graphics.g2d.TextureRegion;
import com.badlogic.gdx.graphics.g2d.BitmapFont.HAlignment; import com.badlogic.gdx.graphics.g2d.BitmapFont.HAlignment;
import com.badlogic.gdx.graphics.g2d.BitmapFont.TextBounds; import com.badlogic.gdx.graphics.g2d.BitmapFont.TextBounds;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.graphics.g2d.TextureRegion;
import com.badlogic.gdx.graphics.glutils.ShapeRenderer; import com.badlogic.gdx.graphics.glutils.ShapeRenderer;
import com.badlogic.gdx.graphics.glutils.ShapeRenderer.ShapeType; import com.badlogic.gdx.graphics.glutils.ShapeRenderer.ShapeType;
import com.badlogic.gdx.math.Matrix4; import com.badlogic.gdx.math.Matrix4;
@@ -17,13 +15,14 @@ import com.badlogic.gdx.math.Rectangle;
import com.badlogic.gdx.math.Vector2; import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.math.Vector3; import com.badlogic.gdx.math.Vector3;
import com.badlogic.gdx.scenes.scene2d.utils.ScissorStack; import com.badlogic.gdx.scenes.scene2d.utils.ScissorStack;
import forge.assets.FImage; import forge.assets.FImage;
import forge.assets.FSkinColor; import forge.assets.FSkinColor;
import forge.assets.FSkinFont; import forge.assets.FSkinFont;
import forge.toolbox.FDisplayObject; import forge.toolbox.FDisplayObject;
import forge.util.Utils; import forge.util.Utils;
import java.util.Stack;
public class Graphics { public class Graphics {
private static final int GL_BLEND = GL20.GL_BLEND; private static final int GL_BLEND = GL20.GL_BLEND;
private static final int GL_LINE_SMOOTH = 2848; //create constant here since not in GL20 private static final int GL_LINE_SMOOTH = 2848; //create constant here since not in GL20
@@ -62,6 +61,10 @@ public class Graphics {
shapeRenderer.dispose(); shapeRenderer.dispose();
} }
public SpriteBatch getBatch() {
return batch;
}
public boolean startClip() { public boolean startClip() {
return startClip(0, 0, bounds.width, bounds.height); return startClip(0, 0, bounds.width, bounds.height);
} }
@@ -667,11 +670,11 @@ public class Graphics {
drawText(text, skinFont, textColor, x, y, w, h, wrap, horzAlignment, centerVertically); drawText(text, skinFont, textColor, x, y, w, h, wrap, horzAlignment, centerVertically);
} }
private float adjustX(float x) { public float adjustX(float x) {
return x + bounds.x; return x + bounds.x;
} }
private float adjustY(float y, float height) { public float adjustY(float y, float height) {
return regionHeight - y - bounds.y - height; //flip y-axis return regionHeight - y - bounds.y - height; //flip y-axis
} }
} }

View File

@@ -1,9 +1,5 @@
package forge.assets; package forge.assets;
import java.io.File;
import java.util.HashMap;
import java.util.Map;
import com.badlogic.gdx.Gdx; import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.files.FileHandle; import com.badlogic.gdx.files.FileHandle;
import com.badlogic.gdx.graphics.Color; import com.badlogic.gdx.graphics.Color;
@@ -20,12 +16,15 @@ import com.badlogic.gdx.graphics.g2d.freetype.FreeTypeFontGenerator;
import com.badlogic.gdx.graphics.g2d.freetype.FreeTypeFontGenerator.FreeTypeFontParameter; import com.badlogic.gdx.graphics.g2d.freetype.FreeTypeFontGenerator.FreeTypeFontParameter;
import com.badlogic.gdx.graphics.glutils.PixmapTextureData; import com.badlogic.gdx.graphics.glutils.PixmapTextureData;
import com.badlogic.gdx.utils.Array; import com.badlogic.gdx.utils.Array;
import forge.FThreads; import forge.FThreads;
import forge.properties.ForgeConstants; import forge.properties.ForgeConstants;
import forge.util.FileUtil; import forge.util.FileUtil;
import forge.util.Utils; import forge.util.Utils;
import java.io.File;
import java.util.HashMap;
import java.util.Map;
public class FSkinFont { public class FSkinFont {
private static final int MIN_FONT_SIZE = 8; private static final int MIN_FONT_SIZE = 8;
private static final int MAX_FONT_SIZE = 72; private static final int MAX_FONT_SIZE = 72;
@@ -127,8 +126,7 @@ public class FSkinFont {
font.setColor(color); font.setColor(color);
if (wrap) { if (wrap) {
font.drawWrapped(batch, text, x, y, w, horzAlignment); font.drawWrapped(batch, text, x, y, w, horzAlignment);
} } else {
else {
font.drawMultiLine(batch, text, x, y, w, horzAlignment); font.drawMultiLine(batch, text, x, y, w, horzAlignment);
} }
} }
@@ -152,8 +150,7 @@ public class FSkinFont {
if (scale != 1) { //re-use font inside range if possible if (scale != 1) { //re-use font inside range if possible
if (fontSize > MAX_FONT_SIZE) { if (fontSize > MAX_FONT_SIZE) {
font = _get(MAX_FONT_SIZE).font; font = _get(MAX_FONT_SIZE).font;
} } else {
else {
font = _get(MIN_FONT_SIZE).font; font = _get(MIN_FONT_SIZE).font;
} }
return; return;
@@ -169,9 +166,7 @@ public class FSkinFont {
font = new BitmapFont(data, (TextureRegion)null, true); font = new BitmapFont(data, (TextureRegion)null, true);
} }
}); });
return; } else {
}
else {
generateFont(FSkin.getSkinFile(TTF_FILE), fontName, fontSize); generateFont(FSkin.getSkinFile(TTF_FILE), fontName, fontSize);
} }
} }

View File

@@ -1,39 +1,46 @@
package forge.card; package forge.card;
import java.util.ArrayList; import com.badlogic.gdx.Gdx;
import java.util.HashMap; import com.badlogic.gdx.files.FileHandle;
import java.util.List;
import java.util.Map;
import org.apache.commons.lang3.StringUtils;
import com.badlogic.gdx.graphics.Color; import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.Pixmap;
import com.badlogic.gdx.graphics.Texture; import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.BitmapFont;
import com.badlogic.gdx.graphics.g2d.BitmapFont.HAlignment; import com.badlogic.gdx.graphics.g2d.BitmapFont.HAlignment;
import com.badlogic.gdx.graphics.g2d.BitmapFont.TextBounds;
import com.badlogic.gdx.graphics.g2d.PixmapPacker;
import com.badlogic.gdx.graphics.g2d.TextureRegion; import com.badlogic.gdx.graphics.g2d.TextureRegion;
import com.badlogic.gdx.graphics.g2d.freetype.FreeTypeFontGenerator;
import com.badlogic.gdx.graphics.g2d.freetype.FreeTypeFontGenerator.FreeTypeFontParameter;
import com.badlogic.gdx.graphics.glutils.PixmapTextureData;
import com.badlogic.gdx.utils.Array;
import forge.FThreads;
import forge.Graphics; import forge.Graphics;
import forge.StaticData; import forge.StaticData;
import forge.assets.FImageComplex; import forge.assets.*;
import forge.assets.FRotatedImage;
import forge.assets.FSkinColor;
import forge.assets.FSkinFont;
import forge.assets.FSkinImage;
import forge.assets.FTextureRegionImage;
import forge.assets.ImageCache;
import forge.card.CardDetailUtil.DetailColors; import forge.card.CardDetailUtil.DetailColors;
import forge.card.CardZoom.ActivateHandler; import forge.card.CardZoom.ActivateHandler;
import forge.card.mana.ManaCost; import forge.card.mana.ManaCost;
import forge.game.card.Card; import forge.game.card.Card;
import forge.game.card.CardView; import forge.game.card.CardView;
import forge.game.card.CardView.CardStateView; import forge.game.card.CardView.CardStateView;
import forge.game.card.CounterType;
import forge.item.IPaperCard; import forge.item.IPaperCard;
import forge.item.PaperCard; import forge.item.PaperCard;
import forge.model.FModel; import forge.model.FModel;
import forge.properties.ForgeConstants;
import forge.properties.ForgeConstants.CounterDisplayType;
import forge.properties.ForgePreferences.FPref; import forge.properties.ForgePreferences.FPref;
import forge.screens.match.MatchController; import forge.screens.match.MatchController;
import forge.toolbox.FList; import forge.toolbox.FList;
import forge.util.Utils; import forge.util.Utils;
import org.apache.commons.lang3.StringUtils;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class CardRenderer { public class CardRenderer {
public enum CardStackPosition { public enum CardStackPosition {
@@ -53,6 +60,16 @@ public class CardRenderer {
private static final float BORDER_THICKNESS = Utils.scale(1); private static final float BORDER_THICKNESS = Utils.scale(1);
public static final float PADDING_MULTIPLIER = 0.021f; public static final float PADDING_MULTIPLIER = 0.021f;
private static BitmapFont counterFont;
private static final Color counterBackgroundColor = new Color(0f, 0f, 0f, 0.9f);
private static final Map<CounterType, Color> counterColorCache = new HashMap<>();
static {
if (counterFont == null) {
generateFontForCounters();
}
}
private static Color fromDetailColor(DetailColors detailColor) { private static Color fromDetailColor(DetailColors detailColor) {
return FSkinColor.fromRGB(detailColor.r, detailColor.g, detailColor.b); return FSkinColor.fromRGB(detailColor.r, detailColor.g, detailColor.b);
} }
@@ -88,10 +105,12 @@ public class CardRenderer {
CardType type = pc.getRules().getType(); CardType type = pc.getRules().getType();
return getCardArt(pc.getImageKey(false), pc.getRules().getSplitType() == CardSplitType.Split, type.isPlane() || type.isPhenomenon(),pc.getRules().getOracleText().contains("Aftermath")); return getCardArt(pc.getImageKey(false), pc.getRules().getSplitType() == CardSplitType.Split, type.isPlane() || type.isPhenomenon(),pc.getRules().getOracleText().contains("Aftermath"));
} }
public static FImageComplex getCardArt(CardView card) { public static FImageComplex getCardArt(CardView card) {
CardTypeView type = card.getCurrentState().getType(); CardTypeView type = card.getCurrentState().getType();
return getCardArt(card.getCurrentState().getImageKey(), card.isSplitCard(), type.isPlane() || type.isPhenomenon(),card.getText().contains("Aftermath")); return getCardArt(card.getCurrentState().getImageKey(), card.isSplitCard(), type.isPlane() || type.isPhenomenon(),card.getText().contains("Aftermath"));
} }
public static FImageComplex getCardArt(String imageKey, boolean isSplitCard, boolean isHorizontalCard, boolean isAftermathCard) { public static FImageComplex getCardArt(String imageKey, boolean isSplitCard, boolean isHorizontalCard, boolean isAftermathCard) {
FImageComplex cardArt = cardArtCache.get(imageKey); FImageComplex cardArt = cardArtCache.get(imageKey);
if (cardArt == null) { if (cardArt == null) {
@@ -181,8 +200,6 @@ public class CardRenderer {
return cardArt; return cardArt;
} }
public static void drawCardListItem(Graphics g, FSkinFont font, FSkinColor foreColor, CardView card, int count, String suffix, float x, float y, float w, float h, boolean compactMode) { public static void drawCardListItem(Graphics g, FSkinFont font, FSkinColor foreColor, CardView card, int count, String suffix, float x, float y, float w, float h, boolean compactMode) {
final CardStateView state = card.getCurrentState(); final CardStateView state = card.getCurrentState();
if (card.getId() > 0) { if (card.getId() > 0) {
@@ -201,6 +218,7 @@ public class CardRenderer {
g.drawText(name, font, foreColor, x, y, w, h, false, HAlignment.CENTER, true); g.drawText(name, font, foreColor, x, y, w, h, false, HAlignment.CENTER, true);
} }
} }
public static void drawCardListItem(Graphics g, FSkinFont font, FSkinColor foreColor, IPaperCard pc, int count, String suffix, float x, float y, float w, float h, boolean compactMode) { public static void drawCardListItem(Graphics g, FSkinFont font, FSkinColor foreColor, IPaperCard pc, int count, String suffix, float x, float y, float w, float h, boolean compactMode) {
final CardView card = CardView.getCardForUi(pc); final CardView card = CardView.getCardForUi(pc);
final CardStateView state = card.getCurrentState(); final CardStateView state = card.getCurrentState();
@@ -208,6 +226,7 @@ public class CardRenderer {
pc.getRarity(), state.getPower(), state.getToughness(), pc.getRarity(), state.getPower(), state.getToughness(),
state.getLoyalty(), count, suffix, x, y, w, h, compactMode); state.getLoyalty(), count, suffix, x, y, w, h, compactMode);
} }
public static void drawCardListItem(Graphics g, FSkinFont font, FSkinColor foreColor, FImageComplex cardArt, CardView card, String set, CardRarity rarity, int power, int toughness, int loyalty, int count, String suffix, float x, float y, float w, float h, boolean compactMode) { public static void drawCardListItem(Graphics g, FSkinFont font, FSkinColor foreColor, FImageComplex cardArt, CardView card, String set, CardRarity rarity, int power, int toughness, int loyalty, int count, String suffix, float x, float y, float w, float h, boolean compactMode) {
float cardArtHeight = h + 2 * FList.PADDING; float cardArtHeight = h + 2 * FList.PADDING;
float cardArtWidth = cardArtHeight * CARD_ART_RATIO; float cardArtWidth = cardArtHeight * CARD_ART_RATIO;
@@ -295,6 +314,7 @@ public class CardRenderer {
} }
return false; return false;
} }
public static boolean paperCardListItemTap(List<?> cards, int selectedIndex, ActivateHandler activateHandler, float x, float y, int count, boolean compactMode) { public static boolean paperCardListItemTap(List<?> cards, int selectedIndex, ActivateHandler activateHandler, float x, float y, int count, boolean compactMode) {
float cardArtHeight = getCardListItemHeight(compactMode); float cardArtHeight = getCardListItemHeight(compactMode);
float cardArtWidth = cardArtHeight * CARD_ART_RATIO; float cardArtWidth = cardArtHeight * CARD_ART_RATIO;
@@ -337,6 +357,7 @@ public class CardRenderer {
g.fillRect(Color.BLACK, x, y, w, h); g.fillRect(Color.BLACK, x, y, w, h);
} }
} }
public static void drawCard(Graphics g, CardView card, float x, float y, float w, float h, CardStackPosition pos) { public static void drawCard(Graphics g, CardView card, float x, float y, float w, float h, CardStackPosition pos) {
Texture image = ImageCache.getImage(card); Texture image = ImageCache.getImage(card);
if (image != null) { if (image != null) {
@@ -406,36 +427,28 @@ public class CardRenderer {
g.drawOutlinedText(String.valueOf(card.getId()), idFont, Color.WHITE, Color.BLACK, x + padding, y + h - idHeight - padding, w, h, false, HAlignment.LEFT, false); g.drawOutlinedText(String.valueOf(card.getId()), idFont, Color.WHITE, Color.BLACK, x + padding, y + h - idHeight - padding, w, h, false, HAlignment.LEFT, false);
} }
int number = 0; if (card.getCounters() != null && !card.getCounters().isEmpty()) {
if (card.getCounters() != null) {
for (final Integer i : card.getCounters().values()) { switch (CounterDisplayType.from(FModel.getPreferences().getPref(FPref.UI_CARD_COUNTER_DISPLAY_TYPE))) {
number += i.intValue(); case OLD_WHEN_SMALL:
} case TEXT:
drawCounterTabs(card, g, x, y, w, h);
break;
case IMAGE:
drawCounterImage(card, g, x, y, w, h);
break;
case HYBRID:
drawCounterImage(card, g, x, y, w, h);
drawCounterTabs(card, g, x, y, w, h);
break;
} }
final int counters = number;
float countersSize = w / 2;
final float xCounters = x - countersSize / 2;
final float yCounters = y + h * 2 / 3 - countersSize;
if (counters == 1) {
CardFaceSymbols.drawSymbol("counters1", g, xCounters, yCounters, countersSize, countersSize);
}
else if (counters == 2) {
CardFaceSymbols.drawSymbol("counters2", g, xCounters, yCounters, countersSize, countersSize);
}
else if (counters == 3) {
CardFaceSymbols.drawSymbol("counters3", g, xCounters, yCounters, countersSize, countersSize);
}
else if (counters > 3) {
CardFaceSymbols.drawSymbol("countersMulti", g, xCounters, yCounters, countersSize, countersSize);
} }
float otherSymbolsSize = w / 2; float otherSymbolsSize = w / 3.5f;
final float combatXSymbols = (x + (w / 4)) - otherSymbolsSize / 2; final float combatXSymbols = (x + (w / 4)) - otherSymbolsSize / 2 - 10;
final float stateXSymbols = (x + (w / 2)) - otherSymbolsSize / 2; final float stateXSymbols = (x + (w / 2)) - otherSymbolsSize / 2 - 10;
final float ySymbols = (y + h) - (h / 8) - otherSymbolsSize / 2; final float ySymbols = (y + h) - (h / 12) - otherSymbolsSize / 2;
if (card.isAttacking()) { if (card.isAttacking()) {
CardFaceSymbols.drawSymbol("attack", g, combatXSymbols, ySymbols, otherSymbolsSize, otherSymbolsSize); CardFaceSymbols.drawSymbol("attack", g, combatXSymbols, ySymbols, otherSymbolsSize, otherSymbolsSize);
@@ -462,6 +475,111 @@ public class CardRenderer {
//only needed if on top since otherwise P/T will be hidden //only needed if on top since otherwise P/T will be hidden
drawPtBox(g, card, details, color, x, y, w, h); drawPtBox(g, card, details, color, x, y, w, h);
} }
}
private static void drawCounterTabs(final CardView card, final Graphics g, final float x, final float y, final float w, final float h) {
float otherSymbolsSize = w / 3.5f;
final float ySymbols = (h / 12) - otherSymbolsSize / 2;
final float counterBoxHeight = 20;
final float counterBoxBaseWidth = 50;
final float counterBoxSpacing = -4;
final float spaceFromTopOfCard = y + h - counterBoxHeight - counterBoxSpacing - otherSymbolsSize + ySymbols;
int currentCounter = 0;
if (CounterDisplayType.from(FModel.getPreferences().getPref(FPref.UI_CARD_COUNTER_DISPLAY_TYPE)) == CounterDisplayType.OLD_WHEN_SMALL) {
int maxCounters = 0;
for (Integer numberOfCounters : card.getCounters().values()) {
maxCounters = Math.max(maxCounters, numberOfCounters);
}
if (counterBoxBaseWidth + counterFont.getBounds(String.valueOf(maxCounters)).width > w) {
drawCounterImage(card, g, x, y, w, h);
return;
}
}
for (Map.Entry<CounterType, Integer> counterEntry : card.getCounters().entrySet()) {
final CounterType counter = counterEntry.getKey();
final int numberOfCounters = counterEntry.getValue();
final float counterBoxRealWidth = counterBoxBaseWidth + counterFont.getBounds(String.valueOf(numberOfCounters)).width + 4;
final float counterYOffset = spaceFromTopOfCard - (currentCounter++ * (counterBoxHeight + counterBoxSpacing));
g.fillRect(counterBackgroundColor, x - 2, counterYOffset, counterBoxRealWidth, counterBoxHeight);
if (!counterColorCache.containsKey(counter)) {
counterColorCache.put(counter, new Color(counter.getRed() / 255.0f, counter.getGreen() / 255.0f, counter.getBlue() / 255.0f, 1.0f));
}
Color counterColor = counterColorCache.get(counter);
drawText(g, counter.getCounterOnCardDisplayName(), counterFont, counterColor, x + 2, counterYOffset, counterBoxRealWidth, counterBoxHeight, HAlignment.LEFT);
drawText(g, String.valueOf(numberOfCounters), counterFont, counterColor, x + counterBoxBaseWidth - 3f, counterYOffset, counterBoxRealWidth, counterBoxHeight, HAlignment.LEFT);
}
}
private static final int GL_BLEND = GL20.GL_BLEND;
private static void drawText(Graphics g, String text, BitmapFont font, Color color, float x, float y, float w, float h, HAlignment horizontalAlignment) {
if (color.a < 1) { //enable blending so alpha colored shapes work properly
Gdx.gl.glEnable(GL_BLEND);
}
TextBounds textBounds = font.getMultiLineBounds(text);
float textHeight = textBounds.height;
if (h > textHeight) {
y += (h - textHeight) / 2;
}
font.setColor(color);
font.drawMultiLine(g.getBatch(), text, g.adjustX(x), g.adjustY(y, 0), w, horizontalAlignment);
if (color.a < 1) {
Gdx.gl.glDisable(GL_BLEND);
}
}
private static void drawCounterImage(final CardView card, final Graphics g, final float x, final float y, final float w, final float h) {
int number = 0;
if (card.getCounters() != null) {
for (final Integer i : card.getCounters().values()) {
number += i;
}
}
final int counters = number;
float countersSize = w / 2;
final float xCounters = x - countersSize / 2;
final float yCounters = y + h * 2 / 3 - countersSize;
if (counters == 1) {
CardFaceSymbols.drawSymbol("counters1", g, xCounters, yCounters, countersSize, countersSize);
}
else if (counters == 2) {
CardFaceSymbols.drawSymbol("counters2", g, xCounters, yCounters, countersSize, countersSize);
}
else if (counters == 3) {
CardFaceSymbols.drawSymbol("counters3", g, xCounters, yCounters, countersSize, countersSize);
}
else if (counters > 3) {
CardFaceSymbols.drawSymbol("countersMulti", g, xCounters, yCounters, countersSize, countersSize);
}
} }
private static void drawPtBox(Graphics g, CardView card, CardStateView details, Color color, float x, float y, float w, float h) { private static void drawPtBox(Graphics g, CardView card, CardStateView details, Color color, float x, float y, float w, float h) {
@@ -564,4 +682,66 @@ public class CardRenderer {
private static boolean showCardIdOverlay(CardView card) { private static boolean showCardIdOverlay(CardView card) {
return card.getId() > 0 && isShowingOverlays(card) && isPreferenceEnabled(FPref.UI_OVERLAY_CARD_ID); return card.getId() > 0 && isShowingOverlays(card) && isPreferenceEnabled(FPref.UI_OVERLAY_CARD_ID);
} }
//TODO Make FSkinFont accept more than one kind of font and merge this with it
private static void generateFontForCounters() {
FileHandle ttfFile = Gdx.files.absolute(ForgeConstants.COMMON_FONTS_DIR).child("Roboto-Bold.ttf");
final int fontSize = 11;
if (!ttfFile.exists()) { return; }
final FreeTypeFontGenerator generator = new FreeTypeFontGenerator(ttfFile);
//approximate optimal page size
int pageSize = 128;
//only generate images for characters that could be used by Forge
String chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890\"!?'.,;:()[]{}<>|/@\\^$-%+=#_&*\u2014\u2022";
final PixmapPacker packer = new PixmapPacker(pageSize, pageSize, Pixmap.Format.RGBA8888, 2, false);
final FreeTypeFontParameter parameter = new FreeTypeFontParameter();
parameter.characters = chars;
parameter.size = fontSize;
parameter.packer = packer;
final FreeTypeFontGenerator.FreeTypeBitmapFontData fontData = generator.generateData(parameter);
final Array<PixmapPacker.Page> pages = packer.getPages();
//finish generating font on UI thread
FThreads.invokeInEdtNowOrLater(new Runnable() {
@Override
public void run() {
TextureRegion[] textureRegions = new TextureRegion[pages.size];
for (int i = 0; i < pages.size; i++) {
PixmapPacker.Page p = pages.get(i);
Texture texture = new Texture(new PixmapTextureData(p.getPixmap(), p.getPixmap().getFormat(), false, false)) {
@Override
public void dispose() {
super.dispose();
getTextureData().consumePixmap().dispose();
}
};
texture.setFilter(Texture.TextureFilter.Nearest, Texture.TextureFilter.Nearest);
textureRegions[i] = new TextureRegion(texture);
}
counterFont = new BitmapFont(fontData, textureRegions, true);
//create .fnt and .png files for font
FileHandle pixmapDir = Gdx.files.absolute(ForgeConstants.FONTS_DIR);
if (pixmapDir != null) {
FileHandle fontFile = pixmapDir.child("Roboto-Bold.fnt");
BitmapFontWriter.setOutputFormat(BitmapFontWriter.OutputFormat.Text);
String[] pageRefs = BitmapFontWriter.writePixmaps(packer.getPages(), pixmapDir, "Roboto-Bold");
BitmapFontWriter.writeFont(counterFont.getData(), pageRefs, fontFile, new BitmapFontWriter.FontInfo("Roboto-Bold", fontSize), 1, 1);
}
generator.dispose();
packer.dispose();
}
});
}
} }

View File

@@ -219,6 +219,14 @@ public class SettingsPage extends TabPage<SettingsScreen> {
ForgeConstants.DISP_CURRENT_COLORS_ALWAYS}), ForgeConstants.DISP_CURRENT_COLORS_ALWAYS}),
4); 4);
lstSettings.addItem(new CustomSelectSetting(FPref.UI_CARD_COUNTER_DISPLAY_TYPE,
"Counter Display Type",
"Selects the style of the in-game counter display for cards. Text-based is a new tab-like display on the cards. Image-based is the old counter image. Hybrid displays both at once.",
new String[]{
ForgeConstants.CounterDisplayType.TEXT.getName(), ForgeConstants.CounterDisplayType.IMAGE.getName(),
ForgeConstants.CounterDisplayType.HYBRID.getName(), ForgeConstants.CounterDisplayType.OLD_WHEN_SMALL.getName()}),
4);
//Card Overlays //Card Overlays
lstSettings.addItem(new BooleanSetting(FPref.UI_SHOW_CARD_OVERLAYS, lstSettings.addItem(new BooleanSetting(FPref.UI_SHOW_CARD_OVERLAYS,
"Show Card Overlays", "Show Card Overlays",

View File

@@ -81,6 +81,7 @@ public final class ForgeConstants {
public static final String CONQUEST_PLANES_DIR = CONQUEST_DIR + "planes" + PATH_SEPARATOR; public static final String CONQUEST_PLANES_DIR = CONQUEST_DIR + "planes" + PATH_SEPARATOR;
public static final String SKINS_DIR = RES_DIR + "skins" + PATH_SEPARATOR; public static final String SKINS_DIR = RES_DIR + "skins" + PATH_SEPARATOR;
public static final String COMMON_FONTS_DIR = RES_DIR + "fonts" + PATH_SEPARATOR;
public static final String DEFAULT_SKINS_DIR = SKINS_DIR + "default" + PATH_SEPARATOR; public static final String DEFAULT_SKINS_DIR = SKINS_DIR + "default" + PATH_SEPARATOR;
//don't associate these skin files with a directory since skin directory will be determined later //don't associate these skin files with a directory since skin directory will be determined later
public static final String SPRITE_ICONS_FILE = "sprite_icons.png"; public static final String SPRITE_ICONS_FILE = "sprite_icons.png";
@@ -203,6 +204,31 @@ public final class ForgeConstants {
public static final String AUTO_YIELD_PER_CARD = "Per Card (Each Game)"; public static final String AUTO_YIELD_PER_CARD = "Per Card (Each Game)";
public static final String AUTO_YIELD_PER_ABILITY = "Per Ability (Each Match)"; public static final String AUTO_YIELD_PER_ABILITY = "Per Ability (Each Match)";
public enum CounterDisplayLocation {
TOP("Top of Card"), BOTTOM("Bottom of Card");
private String name;
CounterDisplayLocation(final String name) {
this.name = name;
}
public String getName() {
return name;
}
public static CounterDisplayLocation from(final String name) {
for (CounterDisplayLocation counterDisplayLocation : values()) {
if (counterDisplayLocation.name.equals(name)) {
return counterDisplayLocation;
}
}
throw new IllegalArgumentException("Counter display location '" + name + "' not found.");
}
}
public enum CounterDisplayType { public enum CounterDisplayType {
/** Use only the new tab-like counter display */ /** Use only the new tab-like counter display */

View File

@@ -92,6 +92,7 @@ public class ForgePreferences extends PreferencesStore<ForgePreferences.FPref> {
UI_AUTO_YIELD_MODE (ForgeConstants.AUTO_YIELD_PER_ABILITY), UI_AUTO_YIELD_MODE (ForgeConstants.AUTO_YIELD_PER_ABILITY),
UI_SHOW_STORM_COUNT_IN_PROMPT ("false"), UI_SHOW_STORM_COUNT_IN_PROMPT ("false"),
UI_CARD_COUNTER_DISPLAY_TYPE(ForgeConstants.CounterDisplayType.TEXT.getName()), UI_CARD_COUNTER_DISPLAY_TYPE(ForgeConstants.CounterDisplayType.TEXT.getName()),
UI_CARD_COUNTER_DISPLAY_LOCATION(ForgeConstants.CounterDisplayLocation.TOP.getName()),
UI_FOR_TOUCHSCREN("false"), UI_FOR_TOUCHSCREN("false"),