mirror of
https://github.com/correl/mage.git
synced 2025-01-11 19:13:02 +00:00
Most obvious bugs ironed out. Ready for PR.
This commit is contained in:
parent
d5415d2d04
commit
d33f8a636e
19 changed files with 415 additions and 101 deletions
|
@ -222,7 +222,7 @@ public class Card extends MagePermanent implements MouseMotionListener, MouseLis
|
|||
}
|
||||
|
||||
@Override
|
||||
public void updateImage() {
|
||||
public void updateArtImage() {
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -114,7 +114,7 @@ public class Cards extends javax.swing.JPanel {
|
|||
setGUISize();
|
||||
for (MageCard mageCard : cards.values()) {
|
||||
mageCard.setCardBounds(0, 0, getCardDimension().width, getCardDimension().height);
|
||||
mageCard.updateImage();
|
||||
mageCard.updateArtImage();
|
||||
mageCard.doLayout();
|
||||
}
|
||||
layoutCards();
|
||||
|
|
|
@ -223,7 +223,7 @@ public abstract class CardPanel extends MagePermanent implements MouseListener,
|
|||
// this calls updateImage
|
||||
toggleTransformed();
|
||||
} else {
|
||||
updateImage();
|
||||
updateArtImage();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -372,7 +372,7 @@ public abstract class CardPanel extends MagePermanent implements MouseListener,
|
|||
setBounds(x - cardXOffset, y - cardYOffset, getWidth(), getHeight());
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
this.cardWidth = cardWidth;
|
||||
this.symbolWidth = cardWidth / 7;
|
||||
this.cardHeight = cardHeight;
|
||||
|
@ -389,8 +389,8 @@ public abstract class CardPanel extends MagePermanent implements MouseListener,
|
|||
int height = -yOffset + rotCenterY + rotCenterToBottomCorner;
|
||||
setBounds(x + xOffset, y + yOffset, width, height);
|
||||
} else {
|
||||
cardXOffset = 5;
|
||||
cardYOffset = 5;
|
||||
cardXOffset = 0;
|
||||
cardYOffset = 0;
|
||||
int width = cardXOffset * 2 + cardWidth;
|
||||
int height = cardYOffset * 2 + cardHeight;
|
||||
setBounds(x - cardXOffset, y - cardYOffset, width, height);
|
||||
|
@ -538,6 +538,11 @@ public abstract class CardPanel extends MagePermanent implements MouseListener,
|
|||
// Update panel attributes
|
||||
this.isChoosable = card.isChoosable();
|
||||
this.isSelected = card.isSelected();
|
||||
|
||||
// Update art?
|
||||
boolean mustUpdateArt =
|
||||
(!gameCard.getName().equals(card.getName())) ||
|
||||
(gameCard.isFaceDown() != card.isFaceDown());
|
||||
|
||||
// Set the new card
|
||||
this.gameCard = card;
|
||||
|
@ -546,8 +551,12 @@ public abstract class CardPanel extends MagePermanent implements MouseListener,
|
|||
String cardType = getType(card);
|
||||
tooltipText.setText(getText(cardType, card));
|
||||
|
||||
// Update the image and transform circle if needed
|
||||
updateImage();
|
||||
// Update the image
|
||||
if (mustUpdateArt) {
|
||||
updateArtImage();
|
||||
}
|
||||
|
||||
// Update transform circle
|
||||
if (card.canTransform()) {
|
||||
BufferedImage transformIcon;
|
||||
if (isTransformed() || card.isTransformed()) {
|
||||
|
@ -783,7 +792,7 @@ public abstract class CardPanel extends MagePermanent implements MouseListener,
|
|||
String temp = this.gameCard.getAlternateName();
|
||||
this.gameCard.setAlternateName(this.gameCard.getOriginalName());
|
||||
this.gameCard.setOriginalName(temp);
|
||||
updateImage();
|
||||
updateArtImage();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
/*
|
||||
* To change this license header, choose License Headers in Project Properties.
|
||||
* To change this template file, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
*/
|
||||
package org.mage.card.arcane;
|
||||
|
||||
/**
|
||||
* @author stravant@gmail.com
|
||||
* Attributes of a card panel outside of the CardView itself that the renderer
|
||||
* needs to know in order to render a card.
|
||||
*/
|
||||
public class CardPanelAttributes {
|
||||
public final int cardWidth;
|
||||
public final int cardHeight;
|
||||
public final boolean isSelected;
|
||||
public final boolean isChoosable;
|
||||
|
||||
public CardPanelAttributes(int cardWidth, int cardHeight, boolean isChoosable, boolean isSelected) {
|
||||
this.cardWidth = cardWidth;
|
||||
this.cardHeight = cardHeight;
|
||||
this.isChoosable = isChoosable;
|
||||
this.isSelected = isSelected;
|
||||
}
|
||||
}
|
|
@ -503,7 +503,7 @@ public class CardPanelComponentImpl extends CardPanel {
|
|||
|
||||
// Update image
|
||||
if (imagePanel != null && imagePanel.getSrcImage() != null) {
|
||||
updateImage();
|
||||
updateArtImage();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -523,15 +523,15 @@ public class CardPanelComponentImpl extends CardPanel {
|
|||
|
||||
///////////////////////////////////////////////////////////
|
||||
// Image updating code
|
||||
private int updateImageStamp;
|
||||
private int updateArtImageStamp;
|
||||
|
||||
@Override
|
||||
public void updateImage() {
|
||||
public void updateArtImage() {
|
||||
tappedAngle = isTapped() ? CardPanel.TAPPED_ANGLE : 0;
|
||||
flippedAngle = isFlipped() ? CardPanel.FLIPPED_ANGLE : 0;
|
||||
|
||||
//final CardView gameCard = this.gameCard;
|
||||
final int stamp = ++updateImageStamp;
|
||||
final int stamp = ++updateArtImageStamp;
|
||||
|
||||
Util.threadPool.submit(new Runnable() {
|
||||
@Override
|
||||
|
@ -548,7 +548,7 @@ public class CardPanelComponentImpl extends CardPanel {
|
|||
UI.invokeLater(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (stamp == updateImageStamp) {
|
||||
if (stamp == updateArtImageStamp) {
|
||||
hasImage = srcImage != null;
|
||||
setText(gameCard);
|
||||
setImage(srcImage);
|
||||
|
|
|
@ -14,6 +14,8 @@ import mage.cards.action.ActionCallback;
|
|||
import mage.client.util.ImageCaches;
|
||||
import mage.constants.CardType;
|
||||
import mage.view.CardView;
|
||||
import mage.view.CounterView;
|
||||
import mage.view.PermanentView;
|
||||
import org.apache.log4j.Logger;
|
||||
import org.jdesktop.swingx.graphics.GraphicsUtilities;
|
||||
import static org.mage.plugins.card.constants.Constants.THUMBNAIL_SIZE_FULL;
|
||||
|
@ -27,6 +29,9 @@ public class CardPanelRenderImpl extends CardPanel {
|
|||
if (a == b) {
|
||||
return true;
|
||||
}
|
||||
if (a.getClass() != b.getClass()) {
|
||||
return false;
|
||||
}
|
||||
if (!a.getName().equals(b.getName())) {
|
||||
return false;
|
||||
}
|
||||
|
@ -60,6 +65,28 @@ public class CardPanelRenderImpl extends CardPanel {
|
|||
if (!a.getExpansionSetCode().equals(b.getExpansionSetCode())) {
|
||||
return false;
|
||||
}
|
||||
if (a.getCounters() == null) {
|
||||
if (b.getCounters() != null) {
|
||||
return false;
|
||||
}
|
||||
} else if (!a.getCounters().equals(b.getCounters())) {
|
||||
return false;
|
||||
}
|
||||
if (a.isFaceDown() != b.isFaceDown()) {
|
||||
return false;
|
||||
}
|
||||
if ((a instanceof PermanentView)) {
|
||||
PermanentView aa = (PermanentView)a;
|
||||
PermanentView bb = (PermanentView)b;
|
||||
if (aa.hasSummoningSickness() != bb.hasSummoningSickness()) {
|
||||
// Note: b must be a permanentview too as we aleady checked that classes
|
||||
// are the same for a and b
|
||||
return false;
|
||||
}
|
||||
if (aa.getDamage() != bb.getDamage()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -91,6 +118,11 @@ public class CardPanelRenderImpl extends CardPanel {
|
|||
sb.append((char)(isChoosable ? 1 : 0));
|
||||
sb.append((char)(this.view.isPlayable() ? 1 : 0));
|
||||
sb.append((char)(this.view.isCanAttack() ? 1 : 0));
|
||||
sb.append((char)(this.view.isFaceDown() ? 1 : 0));
|
||||
if (this.view instanceof PermanentView) {
|
||||
sb.append((char)(((PermanentView)this.view).hasSummoningSickness() ? 1 : 0));
|
||||
sb.append((char)(((PermanentView)this.view).getDamage()));
|
||||
}
|
||||
sb.append(this.view.getName());
|
||||
sb.append(this.view.getPower());
|
||||
sb.append(this.view.getToughness());
|
||||
|
@ -112,6 +144,11 @@ public class CardPanelRenderImpl extends CardPanel {
|
|||
for (String s: this.view.getRules()) {
|
||||
sb.append(s);
|
||||
}
|
||||
if (this.view.getCounters() != null) {
|
||||
for (CounterView v: this.view.getCounters()) {
|
||||
sb.append(v.getName()).append(v.getCount());
|
||||
}
|
||||
}
|
||||
return sb.toString().hashCode();
|
||||
}
|
||||
|
||||
|
@ -207,7 +244,7 @@ public class CardPanelRenderImpl extends CardPanel {
|
|||
}
|
||||
|
||||
// And draw the image we now have
|
||||
g.drawImage(cardImage, 0, 0, null);
|
||||
g.drawImage(cardImage, getCardXOffset(), getCardYOffset(), null);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -217,33 +254,34 @@ public class CardPanelRenderImpl extends CardPanel {
|
|||
private BufferedImage renderCard() {
|
||||
int cardWidth = getCardWidth();
|
||||
int cardHeight = getCardHeight();
|
||||
int cardXOffset = getCardXOffset();
|
||||
int cardYOffset = getCardYOffset();
|
||||
|
||||
// Create image to render to
|
||||
BufferedImage image =
|
||||
GraphicsUtilities.createCompatibleTranslucentImage(getWidth(), getHeight());
|
||||
GraphicsUtilities.createCompatibleTranslucentImage(cardWidth, cardHeight);
|
||||
Graphics2D g2d = image.createGraphics();
|
||||
|
||||
// Render with Antialialsing
|
||||
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
|
||||
|
||||
// Attributes
|
||||
CardPanelAttributes attribs =
|
||||
new CardPanelAttributes(cardWidth, cardHeight, isChoosable(), isSelected());
|
||||
|
||||
// Draw card itself
|
||||
g2d.translate(cardXOffset, cardYOffset);
|
||||
cardRenderer.draw(g2d, cardWidth - cardXOffset, cardHeight - cardYOffset);
|
||||
g2d.translate(-cardXOffset, -cardYOffset);
|
||||
cardRenderer.draw(g2d, attribs);
|
||||
|
||||
// Done
|
||||
g2d.dispose();
|
||||
return image;
|
||||
}
|
||||
|
||||
private int updateImageStamp;
|
||||
private int updateArtImageStamp;
|
||||
@Override
|
||||
public void updateImage() {
|
||||
public void updateArtImage() {
|
||||
// Invalidate
|
||||
artImage = null;
|
||||
cardImage = null;
|
||||
cardRenderer.setArtImage(null);
|
||||
|
||||
// Stop animation
|
||||
tappedAngle = isTapped() ? CardPanel.TAPPED_ANGLE : 0;
|
||||
|
@ -251,43 +289,49 @@ public class CardPanelRenderImpl extends CardPanel {
|
|||
|
||||
// Schedule a repaint
|
||||
repaint();
|
||||
|
||||
// See if the image is already loaded
|
||||
//artImage = ImageCache.tryGetImage(gameCard, getCardWidth(), getCardHeight());
|
||||
//this.cardRenderer.setArtImage(artImage);
|
||||
|
||||
// Submit a task to draw with the card art when it arrives
|
||||
final int stamp = ++updateImageStamp;
|
||||
Util.threadPool.submit(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
final BufferedImage srcImage;
|
||||
if (gameCard.isFaceDown()) {
|
||||
// Nothing to do
|
||||
srcImage = null;
|
||||
} else if (getCardWidth() > THUMBNAIL_SIZE_FULL.width) {
|
||||
srcImage = ImageCache.getImage(gameCard, getCardWidth(), getCardHeight());
|
||||
} else {
|
||||
srcImage = ImageCache.getThumbnail(gameCard);
|
||||
}
|
||||
UI.invokeLater(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (stamp == updateImageStamp) {
|
||||
CardPanelRenderImpl.this.artImage = srcImage;
|
||||
CardPanelRenderImpl.this.cardRenderer.setArtImage(srcImage);
|
||||
if (srcImage != null) {
|
||||
// Invalidate and repaint
|
||||
CardPanelRenderImpl.this.cardImage = null;
|
||||
repaint();
|
||||
if (artImage == null) {
|
||||
final int stamp = ++updateArtImageStamp;
|
||||
Util.threadPool.submit(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
final BufferedImage srcImage;
|
||||
if (gameCard.isFaceDown()) {
|
||||
// Nothing to do
|
||||
srcImage = null;
|
||||
} else if (getCardWidth() > THUMBNAIL_SIZE_FULL.width) {
|
||||
srcImage = ImageCache.getImage(gameCard, getCardWidth(), getCardHeight());
|
||||
} else {
|
||||
srcImage = ImageCache.getThumbnail(gameCard);
|
||||
}
|
||||
UI.invokeLater(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (stamp == updateArtImageStamp) {
|
||||
artImage = srcImage;
|
||||
cardRenderer.setArtImage(srcImage);
|
||||
if (srcImage != null) {
|
||||
// Invalidate and repaint
|
||||
cardImage = null;
|
||||
repaint();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
} catch (Error err) {
|
||||
err.printStackTrace();
|
||||
});
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
} catch (Error err) {
|
||||
err.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -296,7 +340,9 @@ public class CardPanelRenderImpl extends CardPanel {
|
|||
super.update(card);
|
||||
|
||||
// Update renderer
|
||||
cardImage = null;
|
||||
cardRenderer = new ModernCardRenderer(gameCard, isTransformed());
|
||||
cardRenderer.setArtImage(artImage);
|
||||
|
||||
// Repaint
|
||||
repaint();
|
||||
|
@ -304,10 +350,15 @@ public class CardPanelRenderImpl extends CardPanel {
|
|||
|
||||
@Override
|
||||
public void setCardBounds(int x, int y, int cardWidth, int cardHeight) {
|
||||
int oldCardWidth = getCardWidth();
|
||||
int oldCardHeight = getCardHeight();
|
||||
|
||||
super.setCardBounds(x, y, cardWidth, cardHeight);
|
||||
|
||||
// Rerender
|
||||
cardImage = null;
|
||||
// Rerender if card size changed
|
||||
if (getCardWidth() != oldCardWidth || getCardHeight() != oldCardHeight) {
|
||||
cardImage = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -18,9 +18,11 @@ import java.awt.image.BufferedImage;
|
|||
import java.text.AttributedString;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import mage.constants.AbilityType;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.Rarity;
|
||||
import mage.counters.Counter;
|
||||
import mage.utils.CardUtil;
|
||||
import mage.view.CardView;
|
||||
import mage.view.CounterView;
|
||||
import mage.view.PermanentView;
|
||||
|
@ -108,6 +110,10 @@ public abstract class CardRenderer {
|
|||
protected int cardWidth;
|
||||
protected int cardHeight;
|
||||
|
||||
// Is it selectable / selected
|
||||
protected boolean isChoosable;
|
||||
protected boolean isSelected;
|
||||
|
||||
// Radius of the corners of the cards
|
||||
protected static float CORNER_RADIUS_FRAC = 0.1f; //x cardWidth
|
||||
protected static int CORNER_RADIUS_MIN = 3;
|
||||
|
@ -164,17 +170,21 @@ public abstract class CardRenderer {
|
|||
// The Draw Method
|
||||
// The draw method takes the information caculated by the constructor
|
||||
// and uses it to draw to a concrete size of card and graphics.
|
||||
public void draw(Graphics2D g, int cardWidth, int cardHeight) {
|
||||
public void draw(Graphics2D g, CardPanelAttributes attribs) {
|
||||
// Pre template method layout, to calculate shared layout info
|
||||
layout(cardWidth, cardHeight);
|
||||
layout(attribs.cardWidth, attribs.cardHeight);
|
||||
isSelected = attribs.isSelected;
|
||||
isChoosable = attribs.isChoosable;
|
||||
|
||||
// Call the template methods
|
||||
drawBorder(g);
|
||||
drawBackground(g);
|
||||
drawArt(g);
|
||||
drawFrame(g);
|
||||
drawOverlays(g);
|
||||
drawCounters(g);
|
||||
if (!cardView.isAbility()) {
|
||||
drawOverlays(g);
|
||||
drawCounters(g);
|
||||
}
|
||||
}
|
||||
|
||||
// Template methods to be implemented by sub classes
|
||||
|
@ -196,7 +206,7 @@ public abstract class CardRenderer {
|
|||
|
||||
// Draw summoning sickness overlay, and possibly other overlays
|
||||
protected void drawOverlays(Graphics2D g) {
|
||||
if (cardView instanceof PermanentView) {
|
||||
if (CardUtil.isCreature(cardView) && cardView instanceof PermanentView) {
|
||||
if (((PermanentView)cardView).hasSummoningSickness()) {
|
||||
int x1 = (int)(0.2*cardWidth);
|
||||
int x2 = (int)(0.8*cardWidth);
|
||||
|
@ -229,7 +239,7 @@ public abstract class CardRenderer {
|
|||
|
||||
// Draw +1/+1 and other counters
|
||||
protected void drawCounters(Graphics2D g) {
|
||||
int xPos = (int)(0.7*cardWidth);
|
||||
int xPos = (int)(0.65*cardWidth);
|
||||
int yPos = (int)(0.15*cardHeight);
|
||||
if (cardView.getCounters() != null) {
|
||||
for (CounterView v: cardView.getCounters()) {
|
||||
|
@ -245,7 +255,7 @@ public abstract class CardRenderer {
|
|||
} else {
|
||||
p = OTHER_COUNTER_POLY;
|
||||
}
|
||||
double scale = (0.1*0.18*cardWidth);
|
||||
double scale = (0.1*0.25*cardWidth);
|
||||
Graphics2D g2 = (Graphics2D)g.create();
|
||||
g2.translate(xPos, yPos);
|
||||
g2.scale(scale, scale);
|
||||
|
@ -258,7 +268,7 @@ public abstract class CardRenderer {
|
|||
int strW = g2.getFontMetrics().stringWidth(cstr);
|
||||
g2.drawString(cstr, 5 - strW/2, 8);
|
||||
g2.dispose();
|
||||
yPos += ((int)(0.22*cardWidth));
|
||||
yPos += ((int)(0.30*cardWidth));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -324,20 +334,31 @@ public abstract class CardRenderer {
|
|||
|
||||
// Get a string representing the type line
|
||||
protected String getCardTypeLine() {
|
||||
StringBuilder sbType = new StringBuilder();
|
||||
for (String superType : cardView.getSuperTypes()) {
|
||||
sbType.append(superType).append(" ");
|
||||
}
|
||||
for (CardType cardType : cardView.getCardTypes()) {
|
||||
sbType.append(cardType.toString()).append(" ");
|
||||
}
|
||||
if (cardView.getSubTypes().size() > 0) {
|
||||
sbType.append("- ");
|
||||
for (String subType : cardView.getSubTypes()) {
|
||||
sbType.append(subType).append(" ");
|
||||
if (cardView.isAbility()) {
|
||||
switch (cardView.getAbilityType()) {
|
||||
case TRIGGERED:
|
||||
return "Triggered Ability";
|
||||
case ACTIVATED:
|
||||
return "Activated Ability";
|
||||
default:
|
||||
return "??? Ability";
|
||||
}
|
||||
} else {
|
||||
StringBuilder sbType = new StringBuilder();
|
||||
for (String superType : cardView.getSuperTypes()) {
|
||||
sbType.append(superType).append(" ");
|
||||
}
|
||||
for (CardType cardType : cardView.getCardTypes()) {
|
||||
sbType.append(cardType.toString()).append(" ");
|
||||
}
|
||||
if (cardView.getSubTypes().size() > 0) {
|
||||
sbType.append("- ");
|
||||
for (String subType : cardView.getSubTypes()) {
|
||||
sbType.append(subType).append(" ");
|
||||
}
|
||||
}
|
||||
return sbType.toString();
|
||||
}
|
||||
return sbType.toString();
|
||||
}
|
||||
|
||||
// Set the card art image (CardPanel will give it to us when it
|
||||
|
|
|
@ -8,6 +8,7 @@ package org.mage.card.arcane;
|
|||
import java.awt.BasicStroke;
|
||||
import java.awt.Color;
|
||||
import java.awt.Font;
|
||||
import java.awt.FontFormatException;
|
||||
import java.awt.GradientPaint;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.Image;
|
||||
|
@ -22,7 +23,10 @@ import java.awt.font.LineBreakMeasurer;
|
|||
import java.awt.font.TextAttribute;
|
||||
import java.awt.font.TextLayout;
|
||||
import java.awt.font.TextMeasurer;
|
||||
import java.awt.geom.Rectangle2D;
|
||||
import java.awt.geom.RoundRectangle2D;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
import java.text.AttributedCharacterIterator;
|
||||
import java.text.AttributedString;
|
||||
|
@ -35,6 +39,7 @@ import mage.ObjectColor;
|
|||
import mage.constants.CardType;
|
||||
import mage.view.CardView;
|
||||
import mage.view.PermanentView;
|
||||
import net.java.balloontip.styles.RoundedBalloonStyle;
|
||||
import org.apache.log4j.Logger;
|
||||
import org.mage.card.arcane.CardRenderer;
|
||||
import org.mage.card.arcane.CardRendererUtils;
|
||||
|
@ -82,6 +87,20 @@ public class ModernCardRenderer extends CardRenderer {
|
|||
BufferedImage img = CardRendererUtils.toBufferedImage(icon.getImage());
|
||||
return new TexturePaint(img, new Rectangle(0, 0, img.getWidth(), img.getHeight()));
|
||||
}
|
||||
private static Font loadFont(String name) {
|
||||
try {
|
||||
return Font.createFont(
|
||||
Font.TRUETYPE_FONT,
|
||||
ModernCardRenderer.class.getResourceAsStream("/cardrender/" + name + ".ttf"));
|
||||
} catch (IOException e) {
|
||||
LOGGER.info("Failed to load font `" + name + "`, couldn't find resource.");
|
||||
} catch (FontFormatException e) {
|
||||
LOGGER.info("Failed to load font `" + name + "`, bad format.");
|
||||
}
|
||||
return new Font("Arial", Font.PLAIN, 1);
|
||||
}
|
||||
public static Font BASE_BELEREN_FONT = loadFont("beleren-bold");
|
||||
|
||||
public static Paint BG_TEXTURE_WHITE = loadBackgroundTexture("white");
|
||||
public static Paint BG_TEXTURE_BLUE = loadBackgroundTexture("blue");
|
||||
public static Paint BG_TEXTURE_BLACK = loadBackgroundTexture("black");
|
||||
|
@ -152,6 +171,7 @@ public class ModernCardRenderer extends CardRenderer {
|
|||
|
||||
// How far down the card is the type line placed?
|
||||
protected static float TYPE_LINE_Y_FRAC = 0.57f; // x cardHeight
|
||||
protected static float TYPE_LINE_Y_FRAC_TOKEN = 0.70f;
|
||||
protected int typeLineY;
|
||||
|
||||
// How large is the box text, and how far is it down the boxes
|
||||
|
@ -195,17 +215,21 @@ public class ModernCardRenderer extends CardRenderer {
|
|||
BOX_HEIGHT_FRAC * cardHeight);
|
||||
|
||||
// Type line at
|
||||
typeLineY = (int)(TYPE_LINE_Y_FRAC * cardHeight);
|
||||
if (cardView.isToken()) {
|
||||
typeLineY = (int)(TYPE_LINE_Y_FRAC_TOKEN * cardHeight);
|
||||
} else {
|
||||
typeLineY = (int)(TYPE_LINE_Y_FRAC * cardHeight);
|
||||
}
|
||||
|
||||
// Box text height
|
||||
boxTextHeight = getTextHeightForBoxHeight(boxHeight);
|
||||
boxTextOffset = (boxHeight - boxTextHeight)/2;
|
||||
boxTextFont = new Font("Beleren", Font.PLAIN, boxTextHeight);
|
||||
boxTextFont = BASE_BELEREN_FONT.deriveFont(Font.PLAIN, boxTextHeight);
|
||||
|
||||
// Box text height
|
||||
ptTextHeight = getPTTextHeightForLineHeight(boxHeight);
|
||||
ptTextOffset = (boxHeight - ptTextHeight)/2;
|
||||
ptTextFont = new Font("Beleren", Font.PLAIN, ptTextHeight);
|
||||
ptTextFont = BASE_BELEREN_FONT.deriveFont(Font.PLAIN, ptTextHeight);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -213,6 +237,33 @@ public class ModernCardRenderer extends CardRenderer {
|
|||
// Draw border as one rounded rectangle
|
||||
g.setColor(Color.black);
|
||||
g.fillRoundRect(0, 0, cardWidth, cardHeight, cornerRadius, cornerRadius);
|
||||
|
||||
// Selection Borders
|
||||
Color borderColor;
|
||||
if (isSelected) {
|
||||
borderColor = Color.green;
|
||||
} else if (isChoosable) {
|
||||
borderColor = new Color(250, 250, 0, 230);
|
||||
} else if (cardView.isPlayable()) {
|
||||
borderColor = new Color(153, 102, 204, 200);
|
||||
} else if (cardView instanceof PermanentView && ((PermanentView)cardView).isCanAttack()) {
|
||||
borderColor = new Color(0, 0, 255, 230);
|
||||
} else {
|
||||
borderColor = null;
|
||||
}
|
||||
if (borderColor != null) {
|
||||
float hwidth = borderWidth / 2.0f;
|
||||
Graphics2D g2 = (Graphics2D)g.create();
|
||||
g2.setColor(borderColor);
|
||||
g2.setStroke(new BasicStroke(borderWidth));
|
||||
RoundRectangle2D.Float rect
|
||||
= new RoundRectangle2D.Float(
|
||||
hwidth, hwidth,
|
||||
cardWidth - borderWidth, cardHeight - borderWidth,
|
||||
cornerRadius, cornerRadius);
|
||||
g2.draw(rect);
|
||||
g2.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -247,7 +298,7 @@ public class ModernCardRenderer extends CardRenderer {
|
|||
|
||||
@Override
|
||||
protected void drawArt(Graphics2D g) {
|
||||
if (artImage != null) {
|
||||
if (artImage != null && !cardView.isFaceDown()) {
|
||||
int imgWidth = artImage.getWidth();
|
||||
int imgHeight = artImage.getHeight();
|
||||
BufferedImage subImg =
|
||||
|
@ -354,14 +405,29 @@ public class ModernCardRenderer extends CardRenderer {
|
|||
// Draw the name line
|
||||
protected void drawNameLine(Graphics2D g, int x, int y, int w, int h) {
|
||||
// Width of the mana symbols
|
||||
int manaCostWidth = CardRendererUtils.getManaCostWidth(manaCostString, boxTextHeight);
|
||||
|
||||
int manaCostWidth;
|
||||
if (cardView.isAbility()) {
|
||||
manaCostWidth = 0;
|
||||
} else {
|
||||
manaCostWidth = CardRendererUtils.getManaCostWidth(manaCostString, boxTextHeight);
|
||||
}
|
||||
|
||||
// Available width for name. Add a little bit of slop so that one character
|
||||
// can partially go underneath the mana cost
|
||||
int availableWidth = w - manaCostWidth + 2;
|
||||
|
||||
// Draw the name
|
||||
AttributedString str = new AttributedString(cardView.getName());
|
||||
String nameStr;
|
||||
if (cardView.isFaceDown()) {
|
||||
if (cardView instanceof PermanentView && ((PermanentView)cardView).isManifested()) {
|
||||
nameStr = "Manifest: " + cardView.getName();
|
||||
} else {
|
||||
nameStr = "Morph: " + cardView.getName();
|
||||
}
|
||||
} else {
|
||||
nameStr = cardView.getName();
|
||||
}
|
||||
AttributedString str = new AttributedString(nameStr);
|
||||
str.addAttribute(TextAttribute.FONT, boxTextFont);
|
||||
TextMeasurer measure = new TextMeasurer(str.getIterator(), g.getFontRenderContext());
|
||||
TextLayout layout = measure.getLayout(0, measure.getLineBreakIndex(0, availableWidth));
|
||||
|
@ -369,13 +435,20 @@ public class ModernCardRenderer extends CardRenderer {
|
|||
layout.draw(g, x, y + boxTextOffset + boxTextHeight - 1);
|
||||
|
||||
// Draw the mana symbols
|
||||
ManaSymbols.draw(g, manaCostString, x + w - manaCostWidth, y + boxTextOffset, boxTextHeight);
|
||||
if (!cardView.isAbility() && !cardView.isFaceDown()) {
|
||||
ManaSymbols.draw(g, manaCostString, x + w - manaCostWidth, y + boxTextOffset, boxTextHeight);
|
||||
}
|
||||
}
|
||||
|
||||
// Draw the type line (color indicator, types, and expansion symbol)
|
||||
protected void drawTypeLine(Graphics2D g, int x, int y, int w, int h) {
|
||||
// Draw expansion symbol
|
||||
int expansionSymbolWidth = drawExpansionSymbol(g, x, y, w, h);
|
||||
int expansionSymbolWidth;
|
||||
if (cardView.isAbility()) {
|
||||
expansionSymbolWidth = 0;
|
||||
} else {
|
||||
expansionSymbolWidth = drawExpansionSymbol(g, x, y, w, h);
|
||||
}
|
||||
|
||||
// Draw type line text
|
||||
int availableWidth = w - expansionSymbolWidth + 1;
|
||||
|
@ -387,16 +460,23 @@ public class ModernCardRenderer extends CardRenderer {
|
|||
types = types.replace("Legendary", "L.");
|
||||
}
|
||||
|
||||
AttributedString str = new AttributedString(types);
|
||||
str.addAttribute(TextAttribute.FONT, boxTextFont);
|
||||
TextMeasurer measure = new TextMeasurer(str.getIterator(), g.getFontRenderContext());
|
||||
TextLayout layout = measure.getLayout(0, measure.getLineBreakIndex(0, availableWidth));
|
||||
g.setColor(getBoxTextColor());
|
||||
layout.draw(g, x, y + boxTextOffset + boxTextHeight - 1);
|
||||
if (!types.isEmpty()) {
|
||||
AttributedString str = new AttributedString(types);
|
||||
str.addAttribute(TextAttribute.FONT, boxTextFont);
|
||||
TextMeasurer measure = new TextMeasurer(str.getIterator(), g.getFontRenderContext());
|
||||
TextLayout layout = measure.getLayout(0, measure.getLineBreakIndex(0, availableWidth));
|
||||
g.setColor(getBoxTextColor());
|
||||
layout.draw(g, x, y + boxTextOffset + boxTextHeight - 1);
|
||||
}
|
||||
}
|
||||
|
||||
// Draw the P/T and/or Loyalty boxes
|
||||
protected void drawBottomRight(Graphics2D g, Paint borderPaint, Color fill) {
|
||||
// No bottom right for abilities
|
||||
if (cardView.isAbility()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Where to start drawing the things
|
||||
int curY = cardHeight - (int)(0.03f*cardHeight);
|
||||
|
||||
|
@ -493,6 +573,20 @@ public class ModernCardRenderer extends CardRenderer {
|
|||
// Advance
|
||||
curY -= (int)(1.2*y);
|
||||
}
|
||||
|
||||
// does it have damage on it?
|
||||
if ((cardView instanceof PermanentView) && ((PermanentView)cardView).getDamage() > 0) {
|
||||
int x = cardWidth - partWidth - borderWidth;
|
||||
int y = curY - boxHeight;
|
||||
String damage = "" + ((PermanentView)cardView).getDamage();
|
||||
g.setFont(ptTextFont);
|
||||
int txWidth = g.getFontMetrics().stringWidth(damage);
|
||||
g.setColor(Color.red);
|
||||
g.fillRect(x, y, partWidth, boxHeight);
|
||||
g.setColor(Color.white);
|
||||
g.drawRect(x, y, partWidth, boxHeight);
|
||||
g.drawString(damage, x + (partWidth - txWidth)/2, curY - 1);
|
||||
}
|
||||
}
|
||||
|
||||
// Draw the card's textbox in a given rect
|
||||
|
@ -763,6 +857,8 @@ public class ModernCardRenderer extends CardRenderer {
|
|||
protected Color getBoxTextColor() {
|
||||
if (isNightCard()) {
|
||||
return Color.white;
|
||||
} else if (cardView.isAbility()) {
|
||||
return Color.white;
|
||||
} else {
|
||||
return Color.black;
|
||||
}
|
||||
|
@ -800,8 +896,10 @@ public class ModernCardRenderer extends CardRenderer {
|
|||
}
|
||||
|
||||
// Get the box color for the given colors
|
||||
protected static Color getBoxColor(ObjectColor colors, Collection<CardType> types, boolean isNightCard) {
|
||||
if (colors.getColorCount() == 2 && types.contains(CardType.LAND)) {
|
||||
protected Color getBoxColor(ObjectColor colors, Collection<CardType> types, boolean isNightCard) {
|
||||
if (cardView.isAbility()) {
|
||||
return Color.BLACK;
|
||||
} else if (colors.getColorCount() == 2 && types.contains(CardType.LAND)) {
|
||||
// Special case for two color lands. Boxes should be normal land colored
|
||||
// rather than multicolor. Three or greater color lands use a multi-color
|
||||
// box as normal.
|
||||
|
|
|
@ -17,6 +17,7 @@ import java.util.Deque;
|
|||
import java.util.List;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import mage.client.dialog.PreferencesDialog;
|
||||
import mage.view.CardView;
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
|
@ -37,6 +38,11 @@ public class TextboxRuleParser {
|
|||
// representing that information, which can be used to render the rule in
|
||||
// the textbox of a card.
|
||||
public static TextboxRule parse(CardView source, String rule) {
|
||||
// Kill reminder text
|
||||
if (PreferencesDialog.getCachedValue(PreferencesDialog.KEY_CARD_RENDERING_REMINDER_TEXT, "false").equals("false")) {
|
||||
rule = CardRendererUtils.killReminderText(rule);
|
||||
}
|
||||
|
||||
// List of regions to apply
|
||||
ArrayList<TextboxRule.AttributeRegion> regions = new ArrayList<>();
|
||||
|
||||
|
|
|
@ -200,6 +200,10 @@ public class ImageCache {
|
|||
public static BufferedImage getThumbnail(CardView card) {
|
||||
return getImage(getKey(card, card.getName(), "#thumb"));
|
||||
}
|
||||
|
||||
public static BufferedImage tryGetThumbnail(CardView card) {
|
||||
return tryGetImage(getKey(card, card.getName(), "#thumb"));
|
||||
}
|
||||
|
||||
public static BufferedImage getImageOriginal(CardView card) {
|
||||
return getImage(getKey(card, card.getName(), ""));
|
||||
|
@ -230,6 +234,18 @@ public class ImageCache {
|
|||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Image corresponding to the key only if it already exists
|
||||
* in the cache.
|
||||
*/
|
||||
private static BufferedImage tryGetImage(String key) {
|
||||
if (IMAGE_CACHE.containsKey(key)) {
|
||||
return IMAGE_CACHE.get(key);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the map key for a card, without any suffixes for the image size.
|
||||
|
@ -343,6 +359,34 @@ public class ImageCache {
|
|||
|
||||
return TransformedImageCache.getResizedImage(original, (int) (original.getWidth() * scale), (int) (original.getHeight() * scale));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the image appropriate to display for a card in a picture panel, but
|
||||
* only it was ALREADY LOADED. That is, the call is immediate and will not block
|
||||
* on file IO.
|
||||
* @param card
|
||||
* @param width
|
||||
* @param height
|
||||
* @return
|
||||
*/
|
||||
public static BufferedImage tryGetImage(CardView card, int width, int height) {
|
||||
if (Constants.THUMBNAIL_SIZE_FULL.width + 10 > width) {
|
||||
return tryGetThumbnail(card);
|
||||
}
|
||||
String key = getKey(card, card.getName(), Integer.toString(width));
|
||||
BufferedImage original = tryGetImage(key);
|
||||
if (original == null) {
|
||||
LOGGER.debug(key + " not found");
|
||||
return null;
|
||||
}
|
||||
|
||||
double scale = Math.min((double) width / original.getWidth(), (double) height / original.getHeight());
|
||||
if (scale >= 1) {
|
||||
return original;
|
||||
}
|
||||
|
||||
return TransformedImageCache.getResizedImage(original, (int) (original.getWidth() * scale), (int) (original.getHeight() * scale));
|
||||
}
|
||||
|
||||
public static TFile getTFile(String path) {
|
||||
try {
|
||||
|
|
BIN
Mage.Client/src/main/resources/cardrender/beleren-bold.ttf
Normal file
BIN
Mage.Client/src/main/resources/cardrender/beleren-bold.ttf
Normal file
Binary file not shown.
|
@ -32,7 +32,7 @@ public abstract class MageCard extends JPanel {
|
|||
|
||||
public abstract void update(CardView card);
|
||||
|
||||
public abstract void updateImage();
|
||||
public abstract void updateArtImage();
|
||||
|
||||
public abstract Image getImage();
|
||||
|
||||
|
|
|
@ -53,4 +53,21 @@ public class CounterView implements Serializable {
|
|||
public int getCount() {
|
||||
return count;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object other) {
|
||||
if (other == this) {
|
||||
return true;
|
||||
}
|
||||
if (other == null) {
|
||||
return false;
|
||||
}
|
||||
if (!(other instanceof CounterView)) {
|
||||
return false;
|
||||
}
|
||||
CounterView oth = (CounterView)other;
|
||||
return
|
||||
(count == oth.count) &&
|
||||
(name.equals(oth.name));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -38,6 +38,7 @@ import mage.abilities.costs.mana.ManaCost;
|
|||
import mage.abilities.costs.mana.ManaCosts;
|
||||
import mage.abilities.costs.mana.ManaCostsImpl;
|
||||
import mage.abilities.keyword.ChangelingAbility;
|
||||
import mage.abilities.mana.ManaAbility;
|
||||
import mage.constants.CardType;
|
||||
import mage.game.Game;
|
||||
import mage.util.CardUtil;
|
||||
|
@ -176,7 +177,48 @@ public abstract class MageObjectImpl implements MageObject {
|
|||
|
||||
@Override
|
||||
public ObjectColor getFrameColor(Game game) {
|
||||
return frameColor;
|
||||
// For lands, add any colors of mana the land can produce to
|
||||
// its frame colors.
|
||||
if (getCardType().contains(CardType.LAND)) {
|
||||
ObjectColor cl = frameColor.copy();
|
||||
for (Ability ab: getAbilities()) {
|
||||
if (ab instanceof ManaAbility) {
|
||||
ManaAbility mana = (ManaAbility)ab;
|
||||
try {
|
||||
List<Mana> manaAdded = mana.getNetMana(game);
|
||||
for (Mana m: manaAdded) {
|
||||
if (m.getAny() > 0) {
|
||||
return new ObjectColor("WUBRG");
|
||||
}
|
||||
if (m.getWhite() > 0) {
|
||||
cl.setWhite(true);
|
||||
}
|
||||
if (m.getBlue() > 0) {
|
||||
cl.setBlue(true);
|
||||
}
|
||||
if (m.getBlack() > 0) {
|
||||
cl.setBlack(true);
|
||||
}
|
||||
if (m.getRed() > 0) {
|
||||
cl.setRed(true);
|
||||
}
|
||||
if (m.getGreen() > 0) {
|
||||
cl.setGreen(true);
|
||||
}
|
||||
}
|
||||
} catch (NullPointerException e) {
|
||||
// Ability depends on game
|
||||
// but no game passed
|
||||
// All such abilities are 5-color ones
|
||||
return new ObjectColor("WUBRG");
|
||||
}
|
||||
}
|
||||
}
|
||||
return cl;
|
||||
} else {
|
||||
// For everything else, just return the frame colors
|
||||
return frameColor;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -50,7 +50,7 @@ public class MockCard extends CardImpl {
|
|||
if (this.cardType.contains(CardType.PLANESWALKER)) {
|
||||
String startingLoyaltyString = card.getStartingLoyalty();
|
||||
if (startingLoyaltyString.isEmpty()) {
|
||||
Logger.getLogger(MockCard.class).warn("Planeswalker `" + this.name + "` has empty starting loyalty.");
|
||||
//Logger.getLogger(MockCard.class).warn("Planeswalker `" + this.name + "` has empty starting loyalty.");
|
||||
} else {
|
||||
try {
|
||||
this.startingLoyalty = Integer.parseInt(startingLoyaltyString);
|
||||
|
|
|
@ -42,7 +42,6 @@ import mage.ObjectColor;
|
|||
import mage.abilities.Ability;
|
||||
import mage.abilities.SpellAbility;
|
||||
import mage.abilities.common.PlanswalkerEntersWithLoyalityCountersAbility;
|
||||
import mage.abilities.effects.PlaneswalkerRedirectionEffect;
|
||||
import mage.cards.Card;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.mock.MockCard;
|
||||
|
@ -190,7 +189,7 @@ public class CardInfo {
|
|||
}
|
||||
}
|
||||
if (this.startingLoyalty == null) {
|
||||
Logger.getLogger(CardInfo.class).warn("Planeswalker `" + card.getName() + "` missing starting loyalty");
|
||||
//Logger.getLogger(CardInfo.class).warn("Planeswalker `" + card.getName() + "` missing starting loyalty");
|
||||
this.startingLoyalty = "";
|
||||
}
|
||||
} else {
|
||||
|
|
|
@ -61,9 +61,9 @@ public enum CardRepository {
|
|||
private static final String JDBC_URL = "jdbc:h2:file:./db/cards.h2;AUTO_SERVER=TRUE";
|
||||
private static final String VERSION_ENTITY_NAME = "card";
|
||||
// raise this if db structure was changed
|
||||
private static final long CARD_DB_VERSION = 44;
|
||||
private static final long CARD_DB_VERSION = 46;
|
||||
// raise this if new cards were added to the server
|
||||
private static final long CARD_CONTENT_VERSION = 55;
|
||||
private static final long CARD_CONTENT_VERSION = 57;
|
||||
|
||||
private final Random random = new Random();
|
||||
private Dao<CardInfo, Object> cardDao;
|
||||
|
|
|
@ -118,6 +118,7 @@ public class PermanentCard extends PermanentImpl {
|
|||
this.cardType.clear();
|
||||
this.cardType.addAll(card.getCardType());
|
||||
this.color = card.getColor(null).copy();
|
||||
this.frameColor = card.getFrameColor(null).copy();
|
||||
this.manaCost = card.getManaCost().copy();
|
||||
if (card instanceof PermanentCard) {
|
||||
this.maxLevelCounters = ((PermanentCard) card).maxLevelCounters;
|
||||
|
|
|
@ -82,6 +82,7 @@ public class PermanentToken extends PermanentImpl {
|
|||
}
|
||||
this.cardType = token.getCardType();
|
||||
this.color = token.getColor(game).copy();
|
||||
this.frameColor = token.getFrameColor(game);
|
||||
this.power.modifyBaseValue(token.getPower().getBaseValueModified());
|
||||
this.toughness.modifyBaseValue(token.getToughness().getBaseValueModified());
|
||||
this.supertype = token.getSupertype();
|
||||
|
|
Loading…
Reference in a new issue