mirror of
https://github.com/correl/mage.git
synced 2024-12-25 11:11:16 +00:00
* Fixed hybrid mana symbol display for characteristic-based card rendering. Removed not used import statements.
This commit is contained in:
parent
cb91c5b9aa
commit
720a4457fd
9 changed files with 1490 additions and 1523 deletions
|
@ -2,7 +2,6 @@ package org.mage.card.arcane;
|
||||||
|
|
||||||
import java.awt.Color;
|
import java.awt.Color;
|
||||||
import java.awt.Dimension;
|
import java.awt.Dimension;
|
||||||
import java.awt.FlowLayout;
|
|
||||||
import java.awt.Graphics;
|
import java.awt.Graphics;
|
||||||
import java.awt.Graphics2D;
|
import java.awt.Graphics2D;
|
||||||
import java.awt.Point;
|
import java.awt.Point;
|
||||||
|
@ -20,8 +19,6 @@ import java.awt.image.BufferedImage;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import javax.swing.Box;
|
|
||||||
import javax.swing.BoxLayout;
|
|
||||||
import javax.swing.ImageIcon;
|
import javax.swing.ImageIcon;
|
||||||
import javax.swing.JButton;
|
import javax.swing.JButton;
|
||||||
import javax.swing.JPanel;
|
import javax.swing.JPanel;
|
||||||
|
@ -30,7 +27,6 @@ import mage.cards.MagePermanent;
|
||||||
import mage.cards.TextPopup;
|
import mage.cards.TextPopup;
|
||||||
import mage.cards.action.ActionCallback;
|
import mage.cards.action.ActionCallback;
|
||||||
import mage.cards.action.TransferData;
|
import mage.cards.action.TransferData;
|
||||||
import mage.client.components.layout.RelativeLayout;
|
|
||||||
import mage.client.plugins.adapters.MageActionCallback;
|
import mage.client.plugins.adapters.MageActionCallback;
|
||||||
import mage.client.plugins.impl.Plugins;
|
import mage.client.plugins.impl.Plugins;
|
||||||
import mage.client.util.audio.AudioManager;
|
import mage.client.util.audio.AudioManager;
|
||||||
|
@ -75,7 +71,7 @@ public abstract class CardPanel extends MagePermanent implements MouseListener,
|
||||||
public double flippedAngle = 0;
|
public double flippedAngle = 0;
|
||||||
|
|
||||||
private final List<MagePermanent> links = new ArrayList<>();
|
private final List<MagePermanent> links = new ArrayList<>();
|
||||||
|
|
||||||
public JPanel buttonPanel;
|
public JPanel buttonPanel;
|
||||||
private JButton dayNightButton;
|
private JButton dayNightButton;
|
||||||
private JButton showCopySourceButton;
|
private JButton showCopySourceButton;
|
||||||
|
@ -118,7 +114,7 @@ public abstract class CardPanel extends MagePermanent implements MouseListener,
|
||||||
this.gameCard = newGameCard;
|
this.gameCard = newGameCard;
|
||||||
this.callback = callback;
|
this.callback = callback;
|
||||||
this.gameId = gameId;
|
this.gameId = gameId;
|
||||||
|
|
||||||
// Gather info about the card
|
// Gather info about the card
|
||||||
this.isPermanent = this.gameCard instanceof PermanentView;
|
this.isPermanent = this.gameCard instanceof PermanentView;
|
||||||
if (isPermanent) {
|
if (isPermanent) {
|
||||||
|
@ -127,14 +123,14 @@ public abstract class CardPanel extends MagePermanent implements MouseListener,
|
||||||
|
|
||||||
// Set to requested size
|
// Set to requested size
|
||||||
this.setCardBounds(0, 0, dimension.width, dimension.height);
|
this.setCardBounds(0, 0, dimension.width, dimension.height);
|
||||||
|
|
||||||
// Create button panel for Transform and Show Source (copied cards)
|
// Create button panel for Transform and Show Source (copied cards)
|
||||||
buttonPanel = new JPanel();
|
buttonPanel = new JPanel();
|
||||||
buttonPanel.setLayout(null);
|
buttonPanel.setLayout(null);
|
||||||
buttonPanel.setOpaque(false);
|
buttonPanel.setOpaque(false);
|
||||||
buttonPanel.setVisible(true);
|
buttonPanel.setVisible(true);
|
||||||
add(buttonPanel);
|
add(buttonPanel);
|
||||||
|
|
||||||
// Both card rendering implementations have a transform button
|
// Both card rendering implementations have a transform button
|
||||||
if (this.gameCard.canTransform()) {
|
if (this.gameCard.canTransform()) {
|
||||||
// Create the day night button
|
// Create the day night button
|
||||||
|
@ -155,7 +151,7 @@ public abstract class CardPanel extends MagePermanent implements MouseListener,
|
||||||
Animation.transformCard(CardPanel.this, CardPanel.this, true);
|
Animation.transformCard(CardPanel.this, CardPanel.this, true);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Add it
|
// Add it
|
||||||
buttonPanel.add(dayNightButton);
|
buttonPanel.add(dayNightButton);
|
||||||
}
|
}
|
||||||
|
@ -199,14 +195,14 @@ public abstract class CardPanel extends MagePermanent implements MouseListener,
|
||||||
tappedAngle = isTapped() ? CardPanel.TAPPED_ANGLE : 0;
|
tappedAngle = isTapped() ? CardPanel.TAPPED_ANGLE : 0;
|
||||||
flippedAngle = isFlipped() ? CardPanel.FLIPPED_ANGLE : 0;
|
flippedAngle = isFlipped() ? CardPanel.FLIPPED_ANGLE : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void doLayout() {
|
public void doLayout() {
|
||||||
// Position transform and show source buttons
|
// Position transform and show source buttons
|
||||||
buttonPanel.setLocation(cardXOffset, cardYOffset);
|
buttonPanel.setLocation(cardXOffset, cardYOffset);
|
||||||
buttonPanel.setSize(cardWidth, cardHeight);
|
buttonPanel.setSize(cardWidth, cardHeight);
|
||||||
int x = cardWidth/20;
|
int x = cardWidth / 20;
|
||||||
int y = cardHeight/10;
|
int y = cardHeight / 10;
|
||||||
if (dayNightButton != null) {
|
if (dayNightButton != null) {
|
||||||
dayNightButton.setLocation(x, y);
|
dayNightButton.setLocation(x, y);
|
||||||
y += 25;
|
y += 25;
|
||||||
|
@ -216,9 +212,9 @@ public abstract class CardPanel extends MagePermanent implements MouseListener,
|
||||||
showCopySourceButton.setLocation(x, y);
|
showCopySourceButton.setLocation(x, y);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public final void initialDraw() {
|
public final void initialDraw() {
|
||||||
// Kick off
|
// Kick off
|
||||||
if (gameCard.isTransformed()) {
|
if (gameCard.isTransformed()) {
|
||||||
// this calls updateImage
|
// this calls updateImage
|
||||||
toggleTransformed();
|
toggleTransformed();
|
||||||
|
@ -246,8 +242,8 @@ public abstract class CardPanel extends MagePermanent implements MouseListener,
|
||||||
this.callback = null;
|
this.callback = null;
|
||||||
this.data = null;
|
this.data = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Copy the graphical resources of another CardPanel over to this one,
|
// Copy the graphical resources of another CardPanel over to this one,
|
||||||
// if possible (may not be possible if they have different implementations)
|
// if possible (may not be possible if they have different implementations)
|
||||||
// Used when cards are moving between zones
|
// Used when cards are moving between zones
|
||||||
public abstract void transferResources(CardPanel panel);
|
public abstract void transferResources(CardPanel panel);
|
||||||
|
@ -273,7 +269,7 @@ public abstract class CardPanel extends MagePermanent implements MouseListener,
|
||||||
public void setAnimationPanel(boolean isAnimationPanel) {
|
public void setAnimationPanel(boolean isAnimationPanel) {
|
||||||
this.isAnimationPanel = isAnimationPanel;
|
this.isAnimationPanel = isAnimationPanel;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isAnimationPanel() {
|
public boolean isAnimationPanel() {
|
||||||
return this.isAnimationPanel;
|
return this.isAnimationPanel;
|
||||||
}
|
}
|
||||||
|
@ -282,7 +278,7 @@ public abstract class CardPanel extends MagePermanent implements MouseListener,
|
||||||
public void setSelected(boolean isSelected) {
|
public void setSelected(boolean isSelected) {
|
||||||
this.isSelected = isSelected;
|
this.isSelected = isSelected;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isSelected() {
|
public boolean isSelected() {
|
||||||
return this.isSelected;
|
return this.isSelected;
|
||||||
}
|
}
|
||||||
|
@ -291,16 +287,16 @@ public abstract class CardPanel extends MagePermanent implements MouseListener,
|
||||||
public List<MagePermanent> getLinks() {
|
public List<MagePermanent> getLinks() {
|
||||||
return links;
|
return links;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setChoosable(boolean isChoosable) {
|
public void setChoosable(boolean isChoosable) {
|
||||||
this.isChoosable = isChoosable;
|
this.isChoosable = isChoosable;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isChoosable() {
|
public boolean isChoosable() {
|
||||||
return this.isChoosable;
|
return this.isChoosable;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean hasSickness() {
|
public boolean hasSickness() {
|
||||||
return this.hasSickness;
|
return this.hasSickness;
|
||||||
}
|
}
|
||||||
|
@ -308,7 +304,7 @@ public abstract class CardPanel extends MagePermanent implements MouseListener,
|
||||||
public boolean isPermanent() {
|
public boolean isPermanent() {
|
||||||
return this.isPermanent;
|
return this.isPermanent;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setCardAreaRef(JPanel cardArea) {
|
public void setCardAreaRef(JPanel cardArea) {
|
||||||
this.cardArea = cardArea;
|
this.cardArea = cardArea;
|
||||||
|
@ -317,13 +313,13 @@ public abstract class CardPanel extends MagePermanent implements MouseListener,
|
||||||
public void setShowCastingCost(boolean showCastingCost) {
|
public void setShowCastingCost(boolean showCastingCost) {
|
||||||
this.showCastingCost = showCastingCost;
|
this.showCastingCost = showCastingCost;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean getShowCastingCost() {
|
public boolean getShowCastingCost() {
|
||||||
return this.showCastingCost;
|
return this.showCastingCost;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Overridden by different card rendering styles
|
* Overridden by different card rendering styles
|
||||||
*/
|
*/
|
||||||
protected abstract void paintCard(Graphics2D g);
|
protected abstract void paintCard(Graphics2D g);
|
||||||
|
|
||||||
|
@ -356,7 +352,7 @@ public abstract class CardPanel extends MagePermanent implements MouseListener,
|
||||||
|
|
||||||
// Deferr to subclasses
|
// Deferr to subclasses
|
||||||
paintCard(g2d);
|
paintCard(g2d);
|
||||||
|
|
||||||
// Done, dispose of the context
|
// Done, dispose of the context
|
||||||
g2d.dispose();
|
g2d.dispose();
|
||||||
}
|
}
|
||||||
|
@ -372,7 +368,7 @@ public abstract class CardPanel extends MagePermanent implements MouseListener,
|
||||||
setBounds(x - cardXOffset, y - cardYOffset, getWidth(), getHeight());
|
setBounds(x - cardXOffset, y - cardYOffset, getWidth(), getHeight());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.cardWidth = cardWidth;
|
this.cardWidth = cardWidth;
|
||||||
this.symbolWidth = cardWidth / 7;
|
this.symbolWidth = cardWidth / 7;
|
||||||
this.cardHeight = cardHeight;
|
this.cardHeight = cardHeight;
|
||||||
|
@ -436,7 +432,7 @@ public abstract class CardPanel extends MagePermanent implements MouseListener,
|
||||||
public final int getCardHeight() {
|
public final int getCardHeight() {
|
||||||
return cardHeight;
|
return cardHeight;
|
||||||
}
|
}
|
||||||
|
|
||||||
public final int getSymbolWidth() {
|
public final int getSymbolWidth() {
|
||||||
return symbolWidth;
|
return symbolWidth;
|
||||||
}
|
}
|
||||||
|
@ -510,15 +506,15 @@ public abstract class CardPanel extends MagePermanent implements MouseListener,
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Inheriting classes should implement update(CardView card) by
|
* Inheriting classes should implement update(CardView card) by using this.
|
||||||
* using this. However, they should ALSO call repaint() after the superclass
|
* However, they should ALSO call repaint() after the superclass call to
|
||||||
* call to this function, that can't be done here as the overriders may need
|
* this function, that can't be done here as the overriders may need to do
|
||||||
* to do things both before and after this call before repainting.
|
* things both before and after this call before repainting.
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void update(CardView card) {
|
public void update(CardView card) {
|
||||||
this.updateCard = card;
|
this.updateCard = card;
|
||||||
|
|
||||||
// Animation update
|
// Animation update
|
||||||
if (isPermanent && (card instanceof PermanentView)) {
|
if (isPermanent && (card instanceof PermanentView)) {
|
||||||
boolean needsTapping = isTapped() != ((PermanentView) card).isTapped();
|
boolean needsTapping = isTapped() != ((PermanentView) card).isTapped();
|
||||||
|
@ -538,11 +534,11 @@ public abstract class CardPanel extends MagePermanent implements MouseListener,
|
||||||
// Update panel attributes
|
// Update panel attributes
|
||||||
this.isChoosable = card.isChoosable();
|
this.isChoosable = card.isChoosable();
|
||||||
this.isSelected = card.isSelected();
|
this.isSelected = card.isSelected();
|
||||||
|
|
||||||
// Update art?
|
// Update art?
|
||||||
boolean mustUpdateArt =
|
boolean mustUpdateArt
|
||||||
(!gameCard.getName().equals(card.getName())) ||
|
= (!gameCard.getName().equals(card.getName()))
|
||||||
(gameCard.isFaceDown() != card.isFaceDown());
|
|| (gameCard.isFaceDown() != card.isFaceDown());
|
||||||
|
|
||||||
// Set the new card
|
// Set the new card
|
||||||
this.gameCard = card;
|
this.gameCard = card;
|
||||||
|
@ -550,12 +546,12 @@ public abstract class CardPanel extends MagePermanent implements MouseListener,
|
||||||
// Update tooltip text
|
// Update tooltip text
|
||||||
String cardType = getType(card);
|
String cardType = getType(card);
|
||||||
tooltipText.setText(getText(cardType, card));
|
tooltipText.setText(getText(cardType, card));
|
||||||
|
|
||||||
// Update the image
|
// Update the image
|
||||||
if (mustUpdateArt) {
|
if (mustUpdateArt) {
|
||||||
updateArtImage();
|
updateArtImage();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update transform circle
|
// Update transform circle
|
||||||
if (card.canTransform()) {
|
if (card.canTransform()) {
|
||||||
BufferedImage transformIcon;
|
BufferedImage transformIcon;
|
||||||
|
@ -742,13 +738,13 @@ public abstract class CardPanel extends MagePermanent implements MouseListener,
|
||||||
public void update(PermanentView card) {
|
public void update(PermanentView card) {
|
||||||
this.hasSickness = card.hasSummoningSickness();
|
this.hasSickness = card.hasSummoningSickness();
|
||||||
this.showCopySourceButton.setVisible(card.isCopy());
|
this.showCopySourceButton.setVisible(card.isCopy());
|
||||||
update((CardView)card);
|
update((CardView) card);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public PermanentView getOriginalPermanent() {
|
public PermanentView getOriginalPermanent() {
|
||||||
if (isPermanent) {
|
if (isPermanent) {
|
||||||
return (PermanentView)this.gameCard;
|
return (PermanentView) this.gameCard;
|
||||||
}
|
}
|
||||||
throw new IllegalStateException("Is not permanent.");
|
throw new IllegalStateException("Is not permanent.");
|
||||||
}
|
}
|
||||||
|
@ -835,7 +831,7 @@ public abstract class CardPanel extends MagePermanent implements MouseListener,
|
||||||
public void setTextOffset(int yOffset) {
|
public void setTextOffset(int yOffset) {
|
||||||
yTextOffset = yOffset;
|
yTextOffset = yOffset;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getTextOffset() {
|
public int getTextOffset() {
|
||||||
return yTextOffset;
|
return yTextOffset;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,398 +1,397 @@
|
||||||
package org.mage.card.arcane;
|
package org.mage.card.arcane;
|
||||||
|
|
||||||
import com.google.common.base.Function;
|
import com.google.common.collect.MapMaker;
|
||||||
import com.google.common.collect.MapMaker;
|
import java.awt.Dimension;
|
||||||
import java.awt.Color;
|
import java.awt.Graphics2D;
|
||||||
import java.awt.Dimension;
|
import java.awt.Image;
|
||||||
import java.awt.Graphics2D;
|
import java.awt.RenderingHints;
|
||||||
import java.awt.Image;
|
import java.awt.image.BufferedImage;
|
||||||
import java.awt.RenderingHints;
|
import java.io.File;
|
||||||
import java.awt.image.BufferedImage;
|
import java.util.Map;
|
||||||
import java.io.File;
|
import java.util.UUID;
|
||||||
import java.util.Map;
|
import mage.cards.action.ActionCallback;
|
||||||
import java.util.UUID;
|
import mage.constants.CardType;
|
||||||
import mage.cards.action.ActionCallback;
|
import mage.view.CardView;
|
||||||
import mage.client.util.ImageCaches;
|
import mage.view.CounterView;
|
||||||
import mage.constants.CardType;
|
import mage.view.PermanentView;
|
||||||
import mage.view.CardView;
|
import mage.view.StackAbilityView;
|
||||||
import mage.view.CounterView;
|
import net.java.truevfs.access.TFile;
|
||||||
import mage.view.PermanentView;
|
import org.apache.log4j.Logger;
|
||||||
import mage.view.StackAbilityView;
|
import org.jdesktop.swingx.graphics.GraphicsUtilities;
|
||||||
import net.java.truevfs.access.TFile;
|
import static org.mage.plugins.card.constants.Constants.THUMBNAIL_SIZE_FULL;
|
||||||
import org.apache.log4j.Logger;
|
import org.mage.plugins.card.dl.sources.DirectLinksForDownload;
|
||||||
import org.jdesktop.swingx.graphics.GraphicsUtilities;
|
import org.mage.plugins.card.images.ImageCache;
|
||||||
import static org.mage.plugins.card.constants.Constants.THUMBNAIL_SIZE_FULL;
|
|
||||||
import org.mage.plugins.card.dl.sources.DirectLinksForDownload;
|
public class CardPanelRenderImpl extends CardPanel {
|
||||||
import org.mage.plugins.card.images.ImageCache;
|
|
||||||
|
private static final Logger LOGGER = Logger.getLogger(CardPanelRenderImpl.class);
|
||||||
public class CardPanelRenderImpl extends CardPanel {
|
|
||||||
|
private static boolean cardViewEquals(CardView a, CardView b) {
|
||||||
private static final Logger LOGGER = Logger.getLogger(CardPanelRenderImpl.class);
|
if (a == b) {
|
||||||
|
return true;
|
||||||
private static boolean cardViewEquals(CardView a, CardView b) {
|
}
|
||||||
if (a == b) {
|
if (a.getClass() != b.getClass()) {
|
||||||
return true;
|
return false;
|
||||||
}
|
}
|
||||||
if (a.getClass() != b.getClass()) {
|
if (!a.getName().equals(b.getName())) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!a.getName().equals(b.getName())) {
|
if (!a.getPower().equals(b.getPower())) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!a.getPower().equals(b.getPower())) {
|
if (!a.getToughness().equals(b.getToughness())) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!a.getToughness().equals(b.getToughness())) {
|
if (!a.getLoyalty().equals(b.getLoyalty())) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!a.getLoyalty().equals(b.getLoyalty())) {
|
if (0 != a.getColor().compareTo(b.getColor())) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (0 != a.getColor().compareTo(b.getColor())) {
|
if (!a.getCardTypes().equals(b.getCardTypes())) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!a.getCardTypes().equals(b.getCardTypes())) {
|
if (!a.getSubTypes().equals(b.getSubTypes())) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!a.getSubTypes().equals(b.getSubTypes())) {
|
if (!a.getSuperTypes().equals(b.getSuperTypes())) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!a.getSuperTypes().equals(b.getSuperTypes())) {
|
if (!a.getManaCost().equals(b.getManaCost())) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!a.getManaCost().equals(b.getManaCost())) {
|
if (!a.getRules().equals(b.getRules())) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!a.getRules().equals(b.getRules())) {
|
if (!a.getExpansionSetCode().equals(b.getExpansionSetCode())) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!a.getExpansionSetCode().equals(b.getExpansionSetCode())) {
|
if (a.getCounters() == null) {
|
||||||
return false;
|
if (b.getCounters() != null) {
|
||||||
}
|
return false;
|
||||||
if (a.getCounters() == null) {
|
}
|
||||||
if (b.getCounters() != null) {
|
} else if (!a.getCounters().equals(b.getCounters())) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} else if (!a.getCounters().equals(b.getCounters())) {
|
if (a.isFaceDown() != b.isFaceDown()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (a.isFaceDown() != b.isFaceDown()) {
|
if ((a instanceof PermanentView)) {
|
||||||
return false;
|
PermanentView aa = (PermanentView) a;
|
||||||
}
|
PermanentView bb = (PermanentView) b;
|
||||||
if ((a instanceof PermanentView)) {
|
if (aa.hasSummoningSickness() != bb.hasSummoningSickness()) {
|
||||||
PermanentView aa = (PermanentView)a;
|
// Note: b must be a permanentview too as we aleady checked that classes
|
||||||
PermanentView bb = (PermanentView)b;
|
// are the same for a and b
|
||||||
if (aa.hasSummoningSickness() != bb.hasSummoningSickness()) {
|
return false;
|
||||||
// Note: b must be a permanentview too as we aleady checked that classes
|
}
|
||||||
// are the same for a and b
|
if (aa.getDamage() != bb.getDamage()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (aa.getDamage() != bb.getDamage()) {
|
}
|
||||||
return false;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return true;
|
class ImageKey {
|
||||||
}
|
|
||||||
|
final BufferedImage artImage;
|
||||||
class ImageKey {
|
final int width;
|
||||||
final BufferedImage artImage;
|
final int height;
|
||||||
final int width;
|
final boolean isChoosable;
|
||||||
final int height;
|
final boolean isSelected;
|
||||||
final boolean isChoosable;
|
final CardView view;
|
||||||
final boolean isSelected;
|
final int hashCode;
|
||||||
final CardView view;
|
|
||||||
final int hashCode;
|
public ImageKey(CardView view, BufferedImage artImage, int width, int height, boolean isChoosable, boolean isSelected) {
|
||||||
|
this.view = view;
|
||||||
public ImageKey(CardView view, BufferedImage artImage, int width, int height, boolean isChoosable, boolean isSelected) {
|
this.artImage = artImage;
|
||||||
this.view = view;
|
this.width = width;
|
||||||
this.artImage = artImage;
|
this.height = height;
|
||||||
this.width = width;
|
this.isChoosable = isChoosable;
|
||||||
this.height = height;
|
this.isSelected = isSelected;
|
||||||
this.isChoosable = isChoosable;
|
this.hashCode = hashCodeImpl();
|
||||||
this.isSelected = isSelected;
|
}
|
||||||
this.hashCode = hashCodeImpl();
|
|
||||||
}
|
private int hashCodeImpl() {
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
private int hashCodeImpl() {
|
sb.append((char) (artImage != null ? 1 : 0));
|
||||||
StringBuilder sb = new StringBuilder();
|
sb.append((char) width);
|
||||||
sb.append((char)(artImage != null ? 1 : 0));
|
sb.append((char) height);
|
||||||
sb.append((char)width);
|
sb.append((char) (isSelected ? 1 : 0));
|
||||||
sb.append((char)height);
|
sb.append((char) (isChoosable ? 1 : 0));
|
||||||
sb.append((char)(isSelected ? 1 : 0));
|
sb.append((char) (this.view.isPlayable() ? 1 : 0));
|
||||||
sb.append((char)(isChoosable ? 1 : 0));
|
sb.append((char) (this.view.isCanAttack() ? 1 : 0));
|
||||||
sb.append((char)(this.view.isPlayable() ? 1 : 0));
|
sb.append((char) (this.view.isFaceDown() ? 1 : 0));
|
||||||
sb.append((char)(this.view.isCanAttack() ? 1 : 0));
|
if (this.view instanceof PermanentView) {
|
||||||
sb.append((char)(this.view.isFaceDown() ? 1 : 0));
|
sb.append((char) (((PermanentView) this.view).hasSummoningSickness() ? 1 : 0));
|
||||||
if (this.view instanceof PermanentView) {
|
sb.append((char) (((PermanentView) this.view).getDamage()));
|
||||||
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.getName());
|
sb.append(this.view.getToughness());
|
||||||
sb.append(this.view.getPower());
|
sb.append(this.view.getLoyalty());
|
||||||
sb.append(this.view.getToughness());
|
sb.append(this.view.getColor().toString());
|
||||||
sb.append(this.view.getLoyalty());
|
sb.append(this.view.getExpansionSetCode());
|
||||||
sb.append(this.view.getColor().toString());
|
for (CardType type : this.view.getCardTypes()) {
|
||||||
sb.append(this.view.getExpansionSetCode());
|
sb.append((char) type.ordinal());
|
||||||
for (CardType type: this.view.getCardTypes()) {
|
}
|
||||||
sb.append((char)type.ordinal());
|
for (String s : this.view.getSuperTypes()) {
|
||||||
}
|
sb.append(s);
|
||||||
for (String s: this.view.getSuperTypes()) {
|
}
|
||||||
sb.append(s);
|
for (String s : this.view.getSubTypes()) {
|
||||||
}
|
sb.append(s);
|
||||||
for (String s: this.view.getSubTypes()) {
|
}
|
||||||
sb.append(s);
|
for (String s : this.view.getManaCost()) {
|
||||||
}
|
sb.append(s);
|
||||||
for (String s: this.view.getManaCost()) {
|
}
|
||||||
sb.append(s);
|
for (String s : this.view.getRules()) {
|
||||||
}
|
sb.append(s);
|
||||||
for (String s: this.view.getRules()) {
|
}
|
||||||
sb.append(s);
|
if (this.view.getCounters() != null) {
|
||||||
}
|
for (CounterView v : this.view.getCounters()) {
|
||||||
if (this.view.getCounters() != null) {
|
sb.append(v.getName()).append(v.getCount());
|
||||||
for (CounterView v: this.view.getCounters()) {
|
}
|
||||||
sb.append(v.getName()).append(v.getCount());
|
}
|
||||||
}
|
return sb.toString().hashCode();
|
||||||
}
|
}
|
||||||
return sb.toString().hashCode();
|
|
||||||
}
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
@Override
|
return hashCode;
|
||||||
public int hashCode() {
|
}
|
||||||
return hashCode;
|
|
||||||
}
|
@Override
|
||||||
|
public boolean equals(Object object) {
|
||||||
@Override
|
// Initial checks
|
||||||
public boolean equals(Object object) {
|
if (this == object) {
|
||||||
// Initial checks
|
return true;
|
||||||
if (this == object) {
|
}
|
||||||
return true;
|
if (object == null) {
|
||||||
}
|
return false;
|
||||||
if (object == null) {
|
}
|
||||||
return false;
|
if (!(object instanceof ImageKey)) {
|
||||||
}
|
return false;
|
||||||
if (!(object instanceof ImageKey)) {
|
}
|
||||||
return false;
|
final ImageKey other = (ImageKey) object;
|
||||||
}
|
|
||||||
final ImageKey other = (ImageKey)object;
|
// Compare
|
||||||
|
if ((artImage != null) != (other.artImage != null)) {
|
||||||
// Compare
|
return false;
|
||||||
if ((artImage != null) != (other.artImage != null)) {
|
}
|
||||||
return false;
|
if (width != other.width) {
|
||||||
}
|
return false;
|
||||||
if (width != other.width) {
|
}
|
||||||
return false;
|
if (height != other.height) {
|
||||||
}
|
return false;
|
||||||
if (height != other.height) {
|
}
|
||||||
return false;
|
if (isChoosable != other.isChoosable) {
|
||||||
}
|
return false;
|
||||||
if (isChoosable != other.isChoosable) {
|
}
|
||||||
return false;
|
if (isSelected != other.isSelected) {
|
||||||
}
|
return false;
|
||||||
if (isSelected != other.isSelected) {
|
}
|
||||||
return false;
|
return cardViewEquals(view, other.view);
|
||||||
}
|
}
|
||||||
return cardViewEquals(view, other.view);
|
}
|
||||||
}
|
|
||||||
}
|
// Map of generated images
|
||||||
|
private final static Map<ImageKey, BufferedImage> IMAGE_CACHE = new MapMaker().softValues().makeMap();
|
||||||
// Map of generated images
|
|
||||||
private final static Map<ImageKey, BufferedImage> IMAGE_CACHE = new MapMaker().softValues().makeMap();
|
// The art image for the card, loaded in from the disk
|
||||||
|
private BufferedImage artImage;
|
||||||
// The art image for the card, loaded in from the disk
|
|
||||||
private BufferedImage artImage;
|
// The rendered card image, with or without the art image loaded yet
|
||||||
|
// = null while invalid
|
||||||
// The rendered card image, with or without the art image loaded yet
|
private BufferedImage cardImage;
|
||||||
// = null while invalid
|
private CardRenderer cardRenderer;
|
||||||
private BufferedImage cardImage;
|
|
||||||
private CardRenderer cardRenderer;
|
public CardPanelRenderImpl(CardView newGameCard, UUID gameId, final boolean loadImage, ActionCallback callback, final boolean foil, Dimension dimension) {
|
||||||
|
// Call to super
|
||||||
public CardPanelRenderImpl(CardView newGameCard, UUID gameId, final boolean loadImage, ActionCallback callback, final boolean foil, Dimension dimension) {
|
super(newGameCard, gameId, loadImage, callback, foil, dimension);
|
||||||
// Call to super
|
|
||||||
super(newGameCard, gameId, loadImage, callback, foil, dimension);
|
// Renderer
|
||||||
|
cardRenderer = new ModernCardRenderer(gameCard, isTransformed());
|
||||||
// Renderer
|
|
||||||
cardRenderer = new ModernCardRenderer(gameCard, isTransformed());
|
// Draw the parts
|
||||||
|
initialDraw();
|
||||||
// Draw the parts
|
}
|
||||||
initialDraw();
|
|
||||||
}
|
@Override
|
||||||
|
public void transferResources(CardPanel panel) {
|
||||||
@Override
|
if (panel instanceof CardPanelRenderImpl) {
|
||||||
public void transferResources(CardPanel panel) {
|
CardPanelRenderImpl impl = (CardPanelRenderImpl) panel;
|
||||||
if (panel instanceof CardPanelRenderImpl) {
|
|
||||||
CardPanelRenderImpl impl = (CardPanelRenderImpl)panel;
|
// Use the art image and current rendered image from the card
|
||||||
|
artImage = impl.artImage;
|
||||||
// Use the art image and current rendered image from the card
|
cardRenderer.setArtImage(artImage);
|
||||||
artImage = impl.artImage;
|
cardImage = impl.cardImage;
|
||||||
cardRenderer.setArtImage(artImage);
|
}
|
||||||
cardImage = impl.cardImage;
|
}
|
||||||
}
|
|
||||||
}
|
@Override
|
||||||
|
protected void paintCard(Graphics2D g) {
|
||||||
@Override
|
// Render the card if we don't have an image ready to use
|
||||||
protected void paintCard(Graphics2D g) {
|
if (cardImage == null) {
|
||||||
// Render the card if we don't have an image ready to use
|
// Try to get card image from cache based on our card characteristics
|
||||||
if (cardImage == null) {
|
ImageKey key
|
||||||
// Try to get card image from cache based on our card characteristics
|
= new ImageKey(gameCard, artImage,
|
||||||
ImageKey key =
|
getCardWidth(), getCardHeight(),
|
||||||
new ImageKey(gameCard, artImage,
|
isChoosable(), isSelected());
|
||||||
getCardWidth(), getCardHeight(),
|
cardImage = IMAGE_CACHE.get(key);
|
||||||
isChoosable(), isSelected());
|
|
||||||
cardImage = IMAGE_CACHE.get(key);
|
// No cached copy exists? Render one and cache it
|
||||||
|
if (cardImage == null) {
|
||||||
// No cached copy exists? Render one and cache it
|
cardImage = renderCard();
|
||||||
if (cardImage == null) {
|
IMAGE_CACHE.put(key, cardImage);
|
||||||
cardImage = renderCard();
|
}
|
||||||
IMAGE_CACHE.put(key, cardImage);
|
}
|
||||||
}
|
|
||||||
}
|
// And draw the image we now have
|
||||||
|
g.drawImage(cardImage, getCardXOffset(), getCardYOffset(), null);
|
||||||
// And draw the image we now have
|
}
|
||||||
g.drawImage(cardImage, getCardXOffset(), getCardYOffset(), null);
|
|
||||||
}
|
/**
|
||||||
|
* Render the card to a new BufferedImage at it's current dimensions
|
||||||
/**
|
*
|
||||||
* Render the card to a new BufferedImage at it's current dimensions
|
* @return
|
||||||
* @return
|
*/
|
||||||
*/
|
private BufferedImage renderCard() {
|
||||||
private BufferedImage renderCard() {
|
int cardWidth = getCardWidth();
|
||||||
int cardWidth = getCardWidth();
|
int cardHeight = getCardHeight();
|
||||||
int cardHeight = getCardHeight();
|
|
||||||
|
// Create image to render to
|
||||||
// Create image to render to
|
BufferedImage image
|
||||||
BufferedImage image =
|
= GraphicsUtilities.createCompatibleTranslucentImage(cardWidth, cardHeight);
|
||||||
GraphicsUtilities.createCompatibleTranslucentImage(cardWidth, cardHeight);
|
Graphics2D g2d = image.createGraphics();
|
||||||
Graphics2D g2d = image.createGraphics();
|
|
||||||
|
// Render with Antialialsing
|
||||||
// Render with Antialialsing
|
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
|
||||||
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
|
|
||||||
|
// Attributes
|
||||||
// Attributes
|
CardPanelAttributes attribs
|
||||||
CardPanelAttributes attribs =
|
= new CardPanelAttributes(cardWidth, cardHeight, isChoosable(), isSelected());
|
||||||
new CardPanelAttributes(cardWidth, cardHeight, isChoosable(), isSelected());
|
|
||||||
|
// Draw card itself
|
||||||
// Draw card itself
|
cardRenderer.draw(g2d, attribs);
|
||||||
cardRenderer.draw(g2d, attribs);
|
|
||||||
|
// Done
|
||||||
// Done
|
g2d.dispose();
|
||||||
g2d.dispose();
|
return image;
|
||||||
return image;
|
}
|
||||||
}
|
|
||||||
|
private int updateArtImageStamp;
|
||||||
private int updateArtImageStamp;
|
|
||||||
@Override
|
@Override
|
||||||
public void updateArtImage() {
|
public void updateArtImage() {
|
||||||
// Invalidate
|
// Invalidate
|
||||||
artImage = null;
|
artImage = null;
|
||||||
cardImage = null;
|
cardImage = null;
|
||||||
cardRenderer.setArtImage(null);
|
cardRenderer.setArtImage(null);
|
||||||
|
|
||||||
// Stop animation
|
// Stop animation
|
||||||
tappedAngle = isTapped() ? CardPanel.TAPPED_ANGLE : 0;
|
tappedAngle = isTapped() ? CardPanel.TAPPED_ANGLE : 0;
|
||||||
flippedAngle = isFlipped() ? CardPanel.FLIPPED_ANGLE : 0;
|
flippedAngle = isFlipped() ? CardPanel.FLIPPED_ANGLE : 0;
|
||||||
|
|
||||||
// Schedule a repaint
|
// Schedule a repaint
|
||||||
repaint();
|
repaint();
|
||||||
|
|
||||||
// See if the image is already loaded
|
// See if the image is already loaded
|
||||||
//artImage = ImageCache.tryGetImage(gameCard, getCardWidth(), getCardHeight());
|
//artImage = ImageCache.tryGetImage(gameCard, getCardWidth(), getCardHeight());
|
||||||
//this.cardRenderer.setArtImage(artImage);
|
//this.cardRenderer.setArtImage(artImage);
|
||||||
|
// Submit a task to draw with the card art when it arrives
|
||||||
// Submit a task to draw with the card art when it arrives
|
if (artImage == null) {
|
||||||
if (artImage == null) {
|
final int stamp = ++updateArtImageStamp;
|
||||||
final int stamp = ++updateArtImageStamp;
|
Util.threadPool.submit(new Runnable() {
|
||||||
Util.threadPool.submit(new Runnable() {
|
@Override
|
||||||
@Override
|
public void run() {
|
||||||
public void run() {
|
try {
|
||||||
try {
|
final BufferedImage srcImage;
|
||||||
final BufferedImage srcImage;
|
if (gameCard.isFaceDown()) {
|
||||||
if (gameCard.isFaceDown()) {
|
// Nothing to do
|
||||||
// Nothing to do
|
srcImage = null;
|
||||||
srcImage = null;
|
} else if (getCardWidth() > THUMBNAIL_SIZE_FULL.width) {
|
||||||
} else if (getCardWidth() > THUMBNAIL_SIZE_FULL.width) {
|
srcImage = ImageCache.getImage(gameCard, getCardWidth(), getCardHeight());
|
||||||
srcImage = ImageCache.getImage(gameCard, getCardWidth(), getCardHeight());
|
} else {
|
||||||
} else {
|
srcImage = ImageCache.getThumbnail(gameCard);
|
||||||
srcImage = ImageCache.getThumbnail(gameCard);
|
}
|
||||||
}
|
UI.invokeLater(new Runnable() {
|
||||||
UI.invokeLater(new Runnable() {
|
@Override
|
||||||
@Override
|
public void run() {
|
||||||
public void run() {
|
if (stamp == updateArtImageStamp) {
|
||||||
if (stamp == updateArtImageStamp) {
|
artImage = srcImage;
|
||||||
artImage = srcImage;
|
cardRenderer.setArtImage(srcImage);
|
||||||
cardRenderer.setArtImage(srcImage);
|
if (srcImage != null) {
|
||||||
if (srcImage != null) {
|
// Invalidate and repaint
|
||||||
// Invalidate and repaint
|
cardImage = null;
|
||||||
cardImage = null;
|
repaint();
|
||||||
repaint();
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
});
|
} catch (Exception e) {
|
||||||
} catch (Exception e) {
|
e.printStackTrace();
|
||||||
e.printStackTrace();
|
} catch (Error err) {
|
||||||
} catch (Error err) {
|
err.printStackTrace();
|
||||||
err.printStackTrace();
|
}
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
});
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
@Override
|
||||||
@Override
|
public void update(CardView card) {
|
||||||
public void update(CardView card) {
|
// Update super
|
||||||
// Update super
|
super.update(card);
|
||||||
super.update(card);
|
|
||||||
|
// Update renderer
|
||||||
// Update renderer
|
cardImage = null;
|
||||||
cardImage = null;
|
cardRenderer = new ModernCardRenderer(gameCard, isTransformed());
|
||||||
cardRenderer = new ModernCardRenderer(gameCard, isTransformed());
|
cardRenderer.setArtImage(artImage);
|
||||||
cardRenderer.setArtImage(artImage);
|
|
||||||
|
// Repaint
|
||||||
// Repaint
|
repaint();
|
||||||
repaint();
|
}
|
||||||
}
|
|
||||||
|
@Override
|
||||||
@Override
|
public void setCardBounds(int x, int y, int cardWidth, int cardHeight) {
|
||||||
public void setCardBounds(int x, int y, int cardWidth, int cardHeight) {
|
int oldCardWidth = getCardWidth();
|
||||||
int oldCardWidth = getCardWidth();
|
int oldCardHeight = getCardHeight();
|
||||||
int oldCardHeight = getCardHeight();
|
|
||||||
|
super.setCardBounds(x, y, cardWidth, cardHeight);
|
||||||
super.setCardBounds(x, y, cardWidth, cardHeight);
|
|
||||||
|
// Rerender if card size changed
|
||||||
// Rerender if card size changed
|
if (getCardWidth() != oldCardWidth || getCardHeight() != oldCardHeight) {
|
||||||
if (getCardWidth() != oldCardWidth || getCardHeight() != oldCardHeight) {
|
cardImage = null;
|
||||||
cardImage = null;
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
private BufferedImage getFaceDownImage() {
|
||||||
private BufferedImage getFaceDownImage() {
|
if (isPermanent()) {
|
||||||
if (isPermanent()) {
|
if (((PermanentView) gameCard).isMorphed()) {
|
||||||
if (((PermanentView) gameCard).isMorphed()) {
|
return ImageCache.getMorphImage();
|
||||||
return ImageCache.getMorphImage();
|
} else {
|
||||||
} else {
|
return ImageCache.getManifestImage();
|
||||||
return ImageCache.getManifestImage();
|
}
|
||||||
}
|
} else if (this.gameCard instanceof StackAbilityView) {
|
||||||
} else if (this.gameCard instanceof StackAbilityView) {
|
return ImageCache.getMorphImage();
|
||||||
return ImageCache.getMorphImage();
|
} else {
|
||||||
} else {
|
return ImageCache.loadImage(new TFile(DirectLinksForDownload.outDir + File.separator + DirectLinksForDownload.cardbackFilename));
|
||||||
return ImageCache.loadImage(new TFile(DirectLinksForDownload.outDir + File.separator + DirectLinksForDownload.cardbackFilename));
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
@Override
|
||||||
@Override
|
public Image getImage() {
|
||||||
public Image getImage() {
|
if (artImage != null) {
|
||||||
if (artImage != null) {
|
if (gameCard.isFaceDown()) {
|
||||||
if (gameCard.isFaceDown()) {
|
return getFaceDownImage();
|
||||||
return getFaceDownImage();
|
} else {
|
||||||
} else {
|
return ImageCache.getImageOriginal(gameCard);
|
||||||
return ImageCache.getImageOriginal(gameCard);
|
}
|
||||||
}
|
}
|
||||||
}
|
return null;
|
||||||
return null;
|
}
|
||||||
}
|
|
||||||
|
@Override
|
||||||
@Override
|
public void showCardTitle() {
|
||||||
public void showCardTitle() {
|
// Nothing to do, rendered cards always have a title
|
||||||
// Nothing to do, rendered cards always have a title
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
|
@ -1,382 +1,374 @@
|
||||||
/*
|
/*
|
||||||
* To change this license header, choose License Headers in Project Properties.
|
* To change this license header, choose License Headers in Project Properties.
|
||||||
* To change this template file, choose Tools | Templates
|
* To change this template file, choose Tools | Templates
|
||||||
* and open the template in the editor.
|
* and open the template in the editor.
|
||||||
*/
|
*/
|
||||||
package org.mage.card.arcane;
|
package org.mage.card.arcane;
|
||||||
|
|
||||||
import java.awt.BasicStroke;
|
import java.awt.BasicStroke;
|
||||||
import java.awt.Color;
|
import java.awt.Color;
|
||||||
import java.awt.Font;
|
import java.awt.Font;
|
||||||
import java.awt.FontMetrics;
|
import java.awt.Graphics2D;
|
||||||
import java.awt.Graphics2D;
|
import java.awt.Image;
|
||||||
import java.awt.Image;
|
import java.awt.Paint;
|
||||||
import java.awt.Paint;
|
import java.awt.Polygon;
|
||||||
import java.awt.Polygon;
|
import java.awt.image.BufferedImage;
|
||||||
import java.awt.Rectangle;
|
import java.util.ArrayList;
|
||||||
import java.awt.image.BufferedImage;
|
import mage.client.dialog.PreferencesDialog;
|
||||||
import java.text.AttributedString;
|
import mage.constants.AbilityType;
|
||||||
import java.util.ArrayList;
|
import mage.constants.CardType;
|
||||||
import java.util.List;
|
import mage.utils.CardUtil;
|
||||||
import mage.client.dialog.PreferencesDialog;
|
import mage.view.CardView;
|
||||||
import mage.constants.AbilityType;
|
import mage.view.CounterView;
|
||||||
import mage.constants.CardType;
|
import mage.view.PermanentView;
|
||||||
import mage.constants.Rarity;
|
import org.apache.log4j.Logger;
|
||||||
import mage.counters.Counter;
|
|
||||||
import mage.utils.CardUtil;
|
/**
|
||||||
import mage.view.CardView;
|
* @author stravant@gmail.com
|
||||||
import mage.view.CounterView;
|
*
|
||||||
import mage.view.PermanentView;
|
* Common base class for card renderers for each card frame / card type.
|
||||||
import org.apache.log4j.Logger;
|
*
|
||||||
|
* Follows the template method pattern to implement a new renderer, implement
|
||||||
/**
|
* the following methods (they are called in the following order):
|
||||||
* @author stravant@gmail.com
|
*
|
||||||
*
|
* * drawBorder() Draws the outermost border of the card, white border or black
|
||||||
* Common base class for card renderers for each card frame / card type.
|
* border
|
||||||
*
|
*
|
||||||
* Follows the template method pattern to implement a new renderer, implement
|
* * drawBackground() Draws the background texture / color of the card
|
||||||
* the following methods (they are called in the following order):
|
*
|
||||||
*
|
* * drawArt() Draws the card's art
|
||||||
* * drawBorder()
|
*
|
||||||
* Draws the outermost border of the card, white border or black border
|
* * drawFrame() Draws the card frame (over the art and background)
|
||||||
*
|
*
|
||||||
* * drawBackground()
|
* * drawOverlays() Draws summoning sickness and possible other overlays
|
||||||
* Draws the background texture / color of the card
|
*
|
||||||
*
|
* * drawCounters() Draws counters on the card, such as +1/+1 and -1/-1
|
||||||
* * drawArt()
|
* counters
|
||||||
* Draws the card's art
|
*
|
||||||
*
|
* Predefined methods that the implementations can use:
|
||||||
* * drawFrame()
|
*
|
||||||
* Draws the card frame (over the art and background)
|
* * drawRules(font, bounding box)
|
||||||
*
|
*
|
||||||
* * drawOverlays()
|
* * drawNameLine(font, bounding box)
|
||||||
* Draws summoning sickness and possible other overlays
|
*
|
||||||
*
|
* * drawTypeLine(font, bounding box)
|
||||||
* * drawCounters()
|
*
|
||||||
* Draws counters on the card, such as +1/+1 and -1/-1 counters
|
*/
|
||||||
*
|
public abstract class CardRenderer {
|
||||||
* Predefined methods that the implementations can use:
|
|
||||||
*
|
private static final Logger LOGGER = Logger.getLogger(CardPanel.class);
|
||||||
* * drawRules(font, bounding box)
|
|
||||||
*
|
///////////////////////////////////////////////////////////////////////////
|
||||||
* * drawNameLine(font, bounding box)
|
// Common layout metrics between all cards
|
||||||
*
|
// The card to be rendered
|
||||||
* * drawTypeLine(font, bounding box)
|
protected final CardView cardView;
|
||||||
*
|
|
||||||
*/
|
// Is the card transformed?
|
||||||
public abstract class CardRenderer {
|
protected final boolean isTransformed;
|
||||||
private static final Logger LOGGER = Logger.getLogger(CardPanel.class);
|
|
||||||
|
// The card image
|
||||||
///////////////////////////////////////////////////////////////////////////
|
protected BufferedImage artImage;
|
||||||
// Common layout metrics between all cards
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
// The card to be rendered
|
// Common layout metrics between all cards
|
||||||
protected final CardView cardView;
|
// Polygons for counters
|
||||||
|
private static final Polygon PLUS_COUNTER_POLY = new Polygon(new int[]{
|
||||||
// Is the card transformed?
|
0, 5, 10, 10, 5, 0
|
||||||
protected final boolean isTransformed;
|
}, new int[]{
|
||||||
|
3, 0, 3, 10, 9, 10
|
||||||
// The card image
|
}, 6);
|
||||||
protected BufferedImage artImage;
|
private static final Polygon MINUS_COUNTER_POLY = new Polygon(new int[]{
|
||||||
|
0, 5, 10, 10, 5, 0
|
||||||
///////////////////////////////////////////////////////////////////////////
|
}, new int[]{
|
||||||
// Common layout metrics between all cards
|
0, 1, 0, 7, 10, 7
|
||||||
|
}, 6);
|
||||||
// Polygons for counters
|
private static final Polygon TIME_COUNTER_POLY = new Polygon(new int[]{
|
||||||
private static final Polygon PLUS_COUNTER_POLY = new Polygon(new int[]{
|
0, 10, 8, 10, 0, 2
|
||||||
0, 5, 10, 10, 5, 0
|
}, new int[]{
|
||||||
}, new int[]{
|
0, 0, 5, 10, 10, 5
|
||||||
3, 0, 3, 10, 9, 10
|
}, 6);
|
||||||
}, 6);
|
private static final Polygon OTHER_COUNTER_POLY = new Polygon(new int[]{
|
||||||
private static final Polygon MINUS_COUNTER_POLY = new Polygon(new int[]{
|
1, 9, 9, 1
|
||||||
0, 5, 10, 10, 5, 0
|
}, new int[]{
|
||||||
}, new int[]{
|
1, 1, 9, 9
|
||||||
0, 1, 0, 7, 10, 7
|
}, 4);
|
||||||
}, 6);
|
|
||||||
private static final Polygon TIME_COUNTER_POLY = new Polygon(new int[]{
|
// Paint for a card back
|
||||||
0, 10, 8, 10, 0, 2
|
public static Paint BG_TEXTURE_CARDBACK = new Color(153, 102, 51);
|
||||||
}, new int[]{
|
|
||||||
0, 0, 5, 10, 10, 5
|
// The size of the card
|
||||||
}, 6);
|
protected int cardWidth;
|
||||||
private static final Polygon OTHER_COUNTER_POLY = new Polygon(new int[]{
|
protected int cardHeight;
|
||||||
1, 9, 9, 1
|
|
||||||
}, new int[]{
|
// Is it selectable / selected
|
||||||
1, 1, 9, 9
|
protected boolean isChoosable;
|
||||||
}, 4);
|
protected boolean isSelected;
|
||||||
|
|
||||||
// Paint for a card back
|
// Radius of the corners of the cards
|
||||||
public static Paint BG_TEXTURE_CARDBACK = new Color(153, 102, 51);
|
protected static float CORNER_RADIUS_FRAC = 0.1f; //x cardWidth
|
||||||
|
protected static int CORNER_RADIUS_MIN = 3;
|
||||||
// The size of the card
|
protected int cornerRadius;
|
||||||
protected int cardWidth;
|
|
||||||
protected int cardHeight;
|
// The inset of the actual card from the black / white border around it
|
||||||
|
protected static float BORDER_WIDTH_FRAC = 0.03f; //x cardWidth
|
||||||
// Is it selectable / selected
|
protected static float BORDER_WIDTH_MIN = 2;
|
||||||
protected boolean isChoosable;
|
protected int borderWidth;
|
||||||
protected boolean isSelected;
|
|
||||||
|
// The parsed text of the card
|
||||||
// Radius of the corners of the cards
|
protected ArrayList<TextboxRule> textboxRules = new ArrayList<>();
|
||||||
protected static float CORNER_RADIUS_FRAC = 0.1f; //x cardWidth
|
protected ArrayList<TextboxRule> textboxKeywords = new ArrayList<>();
|
||||||
protected static int CORNER_RADIUS_MIN = 3;
|
|
||||||
protected int cornerRadius;
|
// The Construtor
|
||||||
|
// The constructor should prepare all of the things that it can
|
||||||
// The inset of the actual card from the black / white border around it
|
// without knowing the dimensions that the card will be rendered at.
|
||||||
protected static float BORDER_WIDTH_FRAC = 0.03f; //x cardWidth
|
// Then, the CardRenderer can be called on multiple times to render the
|
||||||
protected static float BORDER_WIDTH_MIN = 2;
|
// card at various sizes (for instance, during animation)
|
||||||
protected int borderWidth;
|
public CardRenderer(CardView card, boolean isTransformed) {
|
||||||
|
// Set base parameters
|
||||||
// The parsed text of the card
|
this.cardView = card;
|
||||||
protected ArrayList<TextboxRule> textboxRules = new ArrayList<>();
|
this.isTransformed = isTransformed;
|
||||||
protected ArrayList<TextboxRule> textboxKeywords = new ArrayList<>();
|
|
||||||
|
// Translate the textbox text
|
||||||
// The Construtor
|
for (String rule : card.getRules()) {
|
||||||
// The constructor should prepare all of the things that it can
|
// Kill reminder text
|
||||||
// without knowing the dimensions that the card will be rendered at.
|
if (PreferencesDialog.getCachedValue(PreferencesDialog.KEY_CARD_RENDERING_REMINDER_TEXT, "false").equals("false")) {
|
||||||
// Then, the CardRenderer can be called on multiple times to render the
|
rule = CardRendererUtils.killReminderText(rule).trim();
|
||||||
// card at various sizes (for instance, during animation)
|
}
|
||||||
public CardRenderer(CardView card, boolean isTransformed) {
|
if (!rule.isEmpty()) {
|
||||||
// Set base parameters
|
TextboxRule tbRule = TextboxRuleParser.parse(card, rule);
|
||||||
this.cardView = card;
|
if (tbRule.type == TextboxRuleType.SIMPLE_KEYWORD) {
|
||||||
this.isTransformed = isTransformed;
|
textboxKeywords.add(tbRule);
|
||||||
|
} else if (tbRule.text.isEmpty()) {
|
||||||
// Translate the textbox text
|
// Nothing to do, rule is empty
|
||||||
for (String rule: card.getRules()) {
|
} else {
|
||||||
// Kill reminder text
|
textboxRules.add(tbRule);
|
||||||
if (PreferencesDialog.getCachedValue(PreferencesDialog.KEY_CARD_RENDERING_REMINDER_TEXT, "false").equals("false")) {
|
}
|
||||||
rule = CardRendererUtils.killReminderText(rule).trim();
|
}
|
||||||
}
|
}
|
||||||
if (!rule.isEmpty()) {
|
}
|
||||||
TextboxRule tbRule = TextboxRuleParser.parse(card, rule);
|
|
||||||
if (tbRule.type == TextboxRuleType.SIMPLE_KEYWORD) {
|
// Layout operation
|
||||||
textboxKeywords.add(tbRule);
|
// Calculate common layout metrics that will be used by several
|
||||||
} else if (tbRule.text.isEmpty()) {
|
// of the operations in the template method.
|
||||||
// Nothing to do, rule is empty
|
protected void layout(int cardWidth, int cardHeight) {
|
||||||
} else {
|
// Store the dimensions for the template methods to use
|
||||||
textboxRules.add(tbRule);
|
this.cardWidth = cardWidth;
|
||||||
}
|
this.cardHeight = cardHeight;
|
||||||
}
|
|
||||||
}
|
// Corner radius and border width
|
||||||
}
|
cornerRadius = (int) Math.max(
|
||||||
|
CORNER_RADIUS_MIN,
|
||||||
// Layout operation
|
CORNER_RADIUS_FRAC * cardWidth);
|
||||||
// Calculate common layout metrics that will be used by several
|
|
||||||
// of the operations in the template method.
|
borderWidth = (int) Math.max(
|
||||||
protected void layout(int cardWidth, int cardHeight) {
|
BORDER_WIDTH_MIN,
|
||||||
// Store the dimensions for the template methods to use
|
BORDER_WIDTH_FRAC * cardWidth);
|
||||||
this.cardWidth = cardWidth;
|
}
|
||||||
this.cardHeight = cardHeight;
|
|
||||||
|
// The Draw Method
|
||||||
// Corner radius and border width
|
// The draw method takes the information caculated by the constructor
|
||||||
cornerRadius = (int)Math.max(
|
// and uses it to draw to a concrete size of card and graphics.
|
||||||
CORNER_RADIUS_MIN,
|
public void draw(Graphics2D g, CardPanelAttributes attribs) {
|
||||||
CORNER_RADIUS_FRAC * cardWidth);
|
// Pre template method layout, to calculate shared layout info
|
||||||
|
layout(attribs.cardWidth, attribs.cardHeight);
|
||||||
borderWidth = (int)Math.max(
|
isSelected = attribs.isSelected;
|
||||||
BORDER_WIDTH_MIN,
|
isChoosable = attribs.isChoosable;
|
||||||
BORDER_WIDTH_FRAC * cardWidth);
|
|
||||||
}
|
// Call the template methods
|
||||||
|
drawBorder(g);
|
||||||
// The Draw Method
|
drawBackground(g);
|
||||||
// The draw method takes the information caculated by the constructor
|
drawArt(g);
|
||||||
// and uses it to draw to a concrete size of card and graphics.
|
drawFrame(g);
|
||||||
public void draw(Graphics2D g, CardPanelAttributes attribs) {
|
if (!cardView.isAbility()) {
|
||||||
// Pre template method layout, to calculate shared layout info
|
drawOverlays(g);
|
||||||
layout(attribs.cardWidth, attribs.cardHeight);
|
drawCounters(g);
|
||||||
isSelected = attribs.isSelected;
|
}
|
||||||
isChoosable = attribs.isChoosable;
|
}
|
||||||
|
|
||||||
// Call the template methods
|
// Template methods to be implemented by sub classes
|
||||||
drawBorder(g);
|
// For instance, for the Modern vs Old border card frames
|
||||||
drawBackground(g);
|
protected abstract void drawBorder(Graphics2D g);
|
||||||
drawArt(g);
|
|
||||||
drawFrame(g);
|
protected abstract void drawBackground(Graphics2D g);
|
||||||
if (!cardView.isAbility()) {
|
|
||||||
drawOverlays(g);
|
protected abstract void drawArt(Graphics2D g);
|
||||||
drawCounters(g);
|
|
||||||
}
|
protected abstract void drawFrame(Graphics2D g);
|
||||||
}
|
|
||||||
|
// Template methods that are possible to override, but unlikely to be
|
||||||
// Template methods to be implemented by sub classes
|
// overridden.
|
||||||
// For instance, for the Modern vs Old border card frames
|
// Draw the card back
|
||||||
protected abstract void drawBorder(Graphics2D g);
|
protected void drawCardBack(Graphics2D g) {
|
||||||
protected abstract void drawBackground(Graphics2D g);
|
g.setPaint(BG_TEXTURE_CARDBACK);
|
||||||
protected abstract void drawArt(Graphics2D g);
|
g.fillRect(borderWidth, borderWidth,
|
||||||
protected abstract void drawFrame(Graphics2D g);
|
cardWidth - 2 * borderWidth, cardHeight - 2 * borderWidth);
|
||||||
|
}
|
||||||
// Template methods that are possible to override, but unlikely to be
|
|
||||||
// overridden.
|
// Draw summoning sickness overlay, and possibly other overlays
|
||||||
|
protected void drawOverlays(Graphics2D g) {
|
||||||
// Draw the card back
|
if (CardUtil.isCreature(cardView) && cardView instanceof PermanentView) {
|
||||||
protected void drawCardBack(Graphics2D g) {
|
if (((PermanentView) cardView).hasSummoningSickness()) {
|
||||||
g.setPaint(BG_TEXTURE_CARDBACK);
|
int x1 = (int) (0.2 * cardWidth);
|
||||||
g.fillRect(borderWidth, borderWidth,
|
int x2 = (int) (0.8 * cardWidth);
|
||||||
cardWidth - 2*borderWidth, cardHeight - 2*borderWidth);
|
int y1 = (int) (0.2 * cardHeight);
|
||||||
}
|
int y2 = (int) (0.8 * cardHeight);
|
||||||
|
int xPoints[] = {
|
||||||
// Draw summoning sickness overlay, and possibly other overlays
|
x1, x2, x1, x2
|
||||||
protected void drawOverlays(Graphics2D g) {
|
};
|
||||||
if (CardUtil.isCreature(cardView) && cardView instanceof PermanentView) {
|
int yPoints[] = {
|
||||||
if (((PermanentView)cardView).hasSummoningSickness()) {
|
y1, y1, y2, y2
|
||||||
int x1 = (int)(0.2*cardWidth);
|
};
|
||||||
int x2 = (int)(0.8*cardWidth);
|
g.setColor(new Color(255, 255, 255, 200));
|
||||||
int y1 = (int)(0.2*cardHeight);
|
g.setStroke(new BasicStroke(7));
|
||||||
int y2 = (int)(0.8*cardHeight);
|
g.drawPolygon(xPoints, yPoints, 4);
|
||||||
int xPoints[] = {
|
g.setColor(new Color(0, 0, 0, 200));
|
||||||
x1, x2, x1, x2
|
g.setStroke(new BasicStroke(5));
|
||||||
};
|
g.drawPolygon(xPoints, yPoints, 4);
|
||||||
int yPoints[] = {
|
g.setStroke(new BasicStroke(1));
|
||||||
y1, y1, y2, y2
|
int[] xPoints2 = {
|
||||||
};
|
x1, x2, cardWidth / 2
|
||||||
g.setColor(new Color(255, 255, 255, 200));
|
};
|
||||||
g.setStroke(new BasicStroke(7));
|
int[] yPoints2 = {
|
||||||
g.drawPolygon(xPoints, yPoints, 4);
|
y1, y1, cardHeight / 2
|
||||||
g.setColor(new Color(0, 0, 0, 200));
|
};
|
||||||
g.setStroke(new BasicStroke(5));
|
g.setColor(new Color(0, 0, 0, 100));
|
||||||
g.drawPolygon(xPoints, yPoints, 4);
|
g.fillPolygon(xPoints2, yPoints2, 3);
|
||||||
g.setStroke(new BasicStroke(1));
|
}
|
||||||
int[] xPoints2 = {
|
}
|
||||||
x1, x2, cardWidth/2
|
}
|
||||||
};
|
|
||||||
int[] yPoints2 = {
|
// Draw +1/+1 and other counters
|
||||||
y1, y1, cardHeight/2
|
protected void drawCounters(Graphics2D g) {
|
||||||
};
|
int xPos = (int) (0.65 * cardWidth);
|
||||||
g.setColor(new Color(0, 0, 0, 100));
|
int yPos = (int) (0.15 * cardHeight);
|
||||||
g.fillPolygon(xPoints2, yPoints2, 3);
|
if (cardView.getCounters() != null) {
|
||||||
}
|
for (CounterView v : cardView.getCounters()) {
|
||||||
}
|
// Don't render loyalty, we do that in the bottom corner
|
||||||
}
|
if (!v.getName().equals("loyalty")) {
|
||||||
|
Polygon p;
|
||||||
// Draw +1/+1 and other counters
|
if (v.getName().equals("+1/+1")) {
|
||||||
protected void drawCounters(Graphics2D g) {
|
p = PLUS_COUNTER_POLY;
|
||||||
int xPos = (int)(0.65*cardWidth);
|
} else if (v.getName().equals("-1/-1")) {
|
||||||
int yPos = (int)(0.15*cardHeight);
|
p = MINUS_COUNTER_POLY;
|
||||||
if (cardView.getCounters() != null) {
|
} else if (v.getName().equals("time")) {
|
||||||
for (CounterView v: cardView.getCounters()) {
|
p = TIME_COUNTER_POLY;
|
||||||
// Don't render loyalty, we do that in the bottom corner
|
} else {
|
||||||
if (!v.getName().equals("loyalty")) {
|
p = OTHER_COUNTER_POLY;
|
||||||
Polygon p;
|
}
|
||||||
if (v.getName().equals("+1/+1")) {
|
double scale = (0.1 * 0.25 * cardWidth);
|
||||||
p = PLUS_COUNTER_POLY;
|
Graphics2D g2 = (Graphics2D) g.create();
|
||||||
} else if (v.getName().equals("-1/-1")) {
|
g2.translate(xPos, yPos);
|
||||||
p = MINUS_COUNTER_POLY;
|
g2.scale(scale, scale);
|
||||||
} else if (v.getName().equals("time")) {
|
g2.setColor(Color.white);
|
||||||
p = TIME_COUNTER_POLY;
|
g2.fillPolygon(p);
|
||||||
} else {
|
g2.setColor(Color.black);
|
||||||
p = OTHER_COUNTER_POLY;
|
g2.drawPolygon(p);
|
||||||
}
|
g2.setFont(new Font("Arial", Font.BOLD, 7));
|
||||||
double scale = (0.1*0.25*cardWidth);
|
String cstr = "" + v.getCount();
|
||||||
Graphics2D g2 = (Graphics2D)g.create();
|
int strW = g2.getFontMetrics().stringWidth(cstr);
|
||||||
g2.translate(xPos, yPos);
|
g2.drawString(cstr, 5 - strW / 2, 8);
|
||||||
g2.scale(scale, scale);
|
g2.dispose();
|
||||||
g2.setColor(Color.white);
|
yPos += ((int) (0.30 * cardWidth));
|
||||||
g2.fillPolygon(p);
|
}
|
||||||
g2.setColor(Color.black);
|
}
|
||||||
g2.drawPolygon(p);
|
}
|
||||||
g2.setFont(new Font("Arial", Font.BOLD, 7));
|
}
|
||||||
String cstr = "" + v.getCount();
|
|
||||||
int strW = g2.getFontMetrics().stringWidth(cstr);
|
// Draw an expansion symbol, right justified, in a given region
|
||||||
g2.drawString(cstr, 5 - strW/2, 8);
|
// Return the width of the drawn symbol
|
||||||
g2.dispose();
|
protected int drawExpansionSymbol(Graphics2D g, int x, int y, int w, int h) {
|
||||||
yPos += ((int)(0.30*cardWidth));
|
// Draw the expansion symbol
|
||||||
}
|
Image setSymbol = ManaSymbols.getSetSymbolImage(cardView.getExpansionSetCode(), cardView.getRarity().getCode());
|
||||||
}
|
int setSymbolWidth;
|
||||||
}
|
if (setSymbol == null) {
|
||||||
}
|
// Don't draw anything when we don't have a set symbol
|
||||||
|
return 0;
|
||||||
// Draw an expansion symbol, right justified, in a given region
|
/*
|
||||||
// Return the width of the drawn symbol
|
// Just draw the as a code
|
||||||
protected int drawExpansionSymbol(Graphics2D g, int x, int y, int w, int h) {
|
String code = cardView.getExpansionSetCode();
|
||||||
// Draw the expansion symbol
|
code = (code != null) ? code.toUpperCase() : "";
|
||||||
Image setSymbol = ManaSymbols.getSetSymbolImage(cardView.getExpansionSetCode(), cardView.getRarity().getCode());
|
FontMetrics metrics = g.getFontMetrics();
|
||||||
int setSymbolWidth;
|
setSymbolWidth = metrics.stringWidth(code);
|
||||||
if (setSymbol == null) {
|
if (cardView.getRarity() == Rarity.COMMON) {
|
||||||
// Don't draw anything when we don't have a set symbol
|
g.setColor(Color.white);
|
||||||
return 0;
|
} else {
|
||||||
/*
|
g.setColor(Color.black);
|
||||||
// Just draw the as a code
|
}
|
||||||
String code = cardView.getExpansionSetCode();
|
g.fillRoundRect(
|
||||||
code = (code != null) ? code.toUpperCase() : "";
|
x + w - setSymbolWidth - 1, y + 2,
|
||||||
FontMetrics metrics = g.getFontMetrics();
|
setSymbolWidth+2, h - 5,
|
||||||
setSymbolWidth = metrics.stringWidth(code);
|
5, 5);
|
||||||
if (cardView.getRarity() == Rarity.COMMON) {
|
g.setColor(getRarityColor());
|
||||||
g.setColor(Color.white);
|
g.drawString(code, x + w - setSymbolWidth, y + h - 3);
|
||||||
} else {
|
*/
|
||||||
g.setColor(Color.black);
|
} else {
|
||||||
}
|
// Draw the set symbol
|
||||||
g.fillRoundRect(
|
int height = setSymbol.getHeight(null);
|
||||||
x + w - setSymbolWidth - 1, y + 2,
|
int scale = 1;
|
||||||
setSymbolWidth+2, h - 5,
|
if (height != -1) {
|
||||||
5, 5);
|
while (height > h + 2) {
|
||||||
g.setColor(getRarityColor());
|
scale *= 2;
|
||||||
g.drawString(code, x + w - setSymbolWidth, y + h - 3);
|
height /= 2;
|
||||||
*/
|
}
|
||||||
} else {
|
}
|
||||||
// Draw the set symbol
|
setSymbolWidth = setSymbol.getWidth(null) / scale;
|
||||||
int height = setSymbol.getHeight(null);
|
g.drawImage(setSymbol,
|
||||||
int scale = 1;
|
x + w - setSymbolWidth, y + (h - height) / 2,
|
||||||
if (height != -1) {
|
setSymbolWidth, height,
|
||||||
while (height > h+2) {
|
null);
|
||||||
scale *= 2;
|
}
|
||||||
height /= 2;
|
return setSymbolWidth;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
setSymbolWidth = setSymbol.getWidth(null) / scale;
|
private Color getRarityColor() {
|
||||||
g.drawImage(setSymbol,
|
switch (cardView.getRarity()) {
|
||||||
x + w - setSymbolWidth, y + (h - height)/2,
|
case RARE:
|
||||||
setSymbolWidth, height,
|
return new Color(255, 191, 0);
|
||||||
null);
|
case UNCOMMON:
|
||||||
}
|
return new Color(192, 192, 192);
|
||||||
return setSymbolWidth;
|
case MYTHIC:
|
||||||
}
|
return new Color(213, 51, 11);
|
||||||
private Color getRarityColor() {
|
case SPECIAL:
|
||||||
switch (cardView.getRarity()) {
|
return new Color(204, 0, 255);
|
||||||
case RARE:
|
case BONUS:
|
||||||
return new Color(255, 191, 0);
|
return new Color(129, 228, 228);
|
||||||
case UNCOMMON:
|
case COMMON:
|
||||||
return new Color(192, 192, 192);
|
default:
|
||||||
case MYTHIC:
|
return Color.black;
|
||||||
return new Color(213, 51, 11);
|
}
|
||||||
case SPECIAL:
|
}
|
||||||
return new Color(204, 0, 255);
|
|
||||||
case BONUS:
|
// Get a string representing the type line
|
||||||
return new Color(129, 228, 228);
|
protected String getCardTypeLine() {
|
||||||
case COMMON:
|
if (cardView.isAbility()) {
|
||||||
default:
|
if (AbilityType.TRIGGERED.equals(cardView.getAbilityType())) {
|
||||||
return Color.black;
|
return "Triggered Ability";
|
||||||
}
|
} else if (AbilityType.ACTIVATED.equals(cardView.getAbilityType())) {
|
||||||
}
|
return "Activated Ability";
|
||||||
|
} else {
|
||||||
// Get a string representing the type line
|
return "??? Ability";
|
||||||
protected String getCardTypeLine() {
|
}
|
||||||
if (cardView.isAbility()) {
|
} else {
|
||||||
if (AbilityType.TRIGGERED.equals(cardView.getAbilityType())) {
|
StringBuilder sbType = new StringBuilder();
|
||||||
return "Triggered Ability";
|
for (String superType : cardView.getSuperTypes()) {
|
||||||
} else if (AbilityType.ACTIVATED.equals(cardView.getAbilityType())) {
|
sbType.append(superType).append(" ");
|
||||||
return "Activated Ability";
|
}
|
||||||
} else {
|
for (CardType cardType : cardView.getCardTypes()) {
|
||||||
return "??? Ability";
|
sbType.append(cardType.toString()).append(" ");
|
||||||
}
|
}
|
||||||
} else {
|
if (cardView.getSubTypes().size() > 0) {
|
||||||
StringBuilder sbType = new StringBuilder();
|
sbType.append("- ");
|
||||||
for (String superType : cardView.getSuperTypes()) {
|
for (String subType : cardView.getSubTypes()) {
|
||||||
sbType.append(superType).append(" ");
|
sbType.append(subType).append(" ");
|
||||||
}
|
}
|
||||||
for (CardType cardType : cardView.getCardTypes()) {
|
}
|
||||||
sbType.append(cardType.toString()).append(" ");
|
return sbType.toString();
|
||||||
}
|
}
|
||||||
if (cardView.getSubTypes().size() > 0) {
|
}
|
||||||
sbType.append("- ");
|
|
||||||
for (String subType : cardView.getSubTypes()) {
|
// Set the card art image (CardPanel will give it to us when it
|
||||||
sbType.append(subType).append(" ");
|
// is loaded and ready)
|
||||||
}
|
public void setArtImage(Image image) {
|
||||||
}
|
artImage = CardRendererUtils.toBufferedImage(image);
|
||||||
return sbType.toString();
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Set the card art image (CardPanel will give it to us when it
|
|
||||||
// is loaded and ready)
|
|
||||||
public void setArtImage(Image image) {
|
|
||||||
artImage = CardRendererUtils.toBufferedImage(image);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -2,20 +2,12 @@ package org.mage.card.arcane;
|
||||||
|
|
||||||
import com.google.common.base.Function;
|
import com.google.common.base.Function;
|
||||||
import com.google.common.collect.MapMaker;
|
import com.google.common.collect.MapMaker;
|
||||||
import javax.swing.*;
|
|
||||||
import java.awt.*;
|
import java.awt.*;
|
||||||
import java.awt.font.FontRenderContext;
|
import java.awt.font.FontRenderContext;
|
||||||
import java.awt.font.LineBreakMeasurer;
|
import java.awt.font.LineBreakMeasurer;
|
||||||
import java.awt.font.TextAttribute;
|
import java.awt.font.TextAttribute;
|
||||||
import java.awt.font.TextLayout;
|
import java.awt.font.TextLayout;
|
||||||
import java.awt.image.BufferedImage;
|
import java.awt.image.BufferedImage;
|
||||||
import java.io.BufferedOutputStream;
|
|
||||||
import java.io.ByteArrayInputStream;
|
|
||||||
import java.io.ByteArrayOutputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.ObjectInputStream;
|
|
||||||
import java.io.ObjectOutputStream;
|
|
||||||
import java.lang.ref.SoftReference;
|
|
||||||
import java.lang.ref.WeakReference;
|
import java.lang.ref.WeakReference;
|
||||||
import java.text.AttributedCharacterIterator;
|
import java.text.AttributedCharacterIterator;
|
||||||
import java.text.AttributedString;
|
import java.text.AttributedString;
|
||||||
|
@ -23,10 +15,12 @@ import java.text.BreakIterator;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
import javax.swing.*;
|
||||||
import mage.client.util.ImageCaches;
|
import mage.client.util.ImageCaches;
|
||||||
import org.jdesktop.swingx.graphics.GraphicsUtilities;
|
import org.jdesktop.swingx.graphics.GraphicsUtilities;
|
||||||
|
|
||||||
public class GlowText extends JLabel {
|
public class GlowText extends JLabel {
|
||||||
|
|
||||||
private static final long serialVersionUID = 1827677946939348001L;
|
private static final long serialVersionUID = 1827677946939348001L;
|
||||||
private int glowSize;
|
private int glowSize;
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
|
@ -36,12 +30,12 @@ public class GlowText extends JLabel {
|
||||||
private int lineCount = 0;
|
private int lineCount = 0;
|
||||||
private static Map<Key, BufferedImage> IMAGE_CACHE;
|
private static Map<Key, BufferedImage> IMAGE_CACHE;
|
||||||
|
|
||||||
private final static class Key
|
private final static class Key {
|
||||||
{
|
|
||||||
final int width;
|
final int width;
|
||||||
final int height;
|
final int height;
|
||||||
final String text;
|
final String text;
|
||||||
final Map<TextAttribute,?> fontAttributes;
|
final Map<TextAttribute, ?> fontAttributes;
|
||||||
final Color color;
|
final Color color;
|
||||||
final int glowSize;
|
final int glowSize;
|
||||||
final float glowIntensity;
|
final float glowIntensity;
|
||||||
|
@ -53,8 +47,9 @@ public class GlowText extends JLabel {
|
||||||
|
|
||||||
Font getFont() {
|
Font getFont() {
|
||||||
Font res = this.originalFont.get();
|
Font res = this.originalFont.get();
|
||||||
if(res == null)
|
if (res == null) {
|
||||||
res = Font.getFont(this.fontAttributes);
|
res = Font.getFont(this.fontAttributes);
|
||||||
|
}
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -138,18 +133,18 @@ public class GlowText extends JLabel {
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setGlow (Color glowColor, int size, float intensity) {
|
public void setGlow(Color glowColor, int size, float intensity) {
|
||||||
this.glowColor = glowColor;
|
this.glowColor = glowColor;
|
||||||
this.glowSize = size;
|
this.glowSize = size;
|
||||||
this.glowIntensity = intensity;
|
this.glowIntensity = intensity;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setWrap (boolean wrap) {
|
public void setWrap(boolean wrap) {
|
||||||
this.wrap = wrap;
|
this.wrap = wrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Dimension getPreferredSize () {
|
public Dimension getPreferredSize() {
|
||||||
Dimension size = super.getPreferredSize();
|
Dimension size = super.getPreferredSize();
|
||||||
size.width += glowSize;
|
size.width += glowSize;
|
||||||
size.height += glowSize / 2;
|
size.height += glowSize / 2;
|
||||||
|
@ -157,7 +152,7 @@ public class GlowText extends JLabel {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void paint (Graphics g) {
|
public void paint(Graphics g) {
|
||||||
if (getText().length() == 0) {
|
if (getText().length() == 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -165,7 +160,7 @@ public class GlowText extends JLabel {
|
||||||
g.drawImage(IMAGE_CACHE.get(new Key(getWidth(), getHeight(), getText(), getFont(), getForeground(), glowSize, glowIntensity, glowColor, wrap)), 0, 0, null);
|
g.drawImage(IMAGE_CACHE.get(new Key(getWidth(), getHeight(), getText(), getFont(), getForeground(), glowSize, glowIntensity, glowColor, wrap)), 0, 0, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static BufferedImage createImage (Key key) {
|
private static BufferedImage createImage(Key key) {
|
||||||
Dimension size = new Dimension(key.width, key.height);
|
Dimension size = new Dimension(key.width, key.height);
|
||||||
BufferedImage image = GraphicsUtilities.createCompatibleTranslucentImage(size.width, size.height);
|
BufferedImage image = GraphicsUtilities.createCompatibleTranslucentImage(size.width, size.height);
|
||||||
Graphics2D g2d = image.createGraphics();
|
Graphics2D g2d = image.createGraphics();
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,28 +1,28 @@
|
||||||
/*
|
/*
|
||||||
* To change this license header, choose License Headers in Project Properties.
|
* To change this license header, choose License Headers in Project Properties.
|
||||||
* To change this template file, choose Tools | Templates
|
* To change this template file, choose Tools | Templates
|
||||||
* and open the template in the editor.
|
* and open the template in the editor.
|
||||||
*/
|
*/
|
||||||
package org.mage.card.arcane;
|
package org.mage.card.arcane;
|
||||||
|
|
||||||
import java.text.AttributedString;
|
import java.util.List;
|
||||||
import java.util.List;
|
|
||||||
|
/**
|
||||||
/**
|
* @author StravantUser
|
||||||
* @author StravantUser
|
*
|
||||||
*
|
* Level rule associated with leveler cards
|
||||||
* Level rule associated with leveler cards
|
*/
|
||||||
*/
|
public class TextboxLevelRule extends TextboxRule {
|
||||||
public class TextboxLevelRule extends TextboxRule {
|
|
||||||
// The levels that this rule applies to
|
// The levels that this rule applies to
|
||||||
public int levelFrom;
|
public int levelFrom;
|
||||||
public int levelTo;
|
public int levelTo;
|
||||||
|
|
||||||
public static int AND_HIGHER = 100;
|
public static int AND_HIGHER = 100;
|
||||||
|
|
||||||
public TextboxLevelRule(String text, List<AttributeRegion> regions, int levelFrom, int levelTo) {
|
public TextboxLevelRule(String text, List<AttributeRegion> regions, int levelFrom, int levelTo) {
|
||||||
super(text, regions, TextboxRuleType.LEVEL);
|
super(text, regions, TextboxRuleType.LEVEL);
|
||||||
this.levelFrom = levelFrom;
|
this.levelFrom = levelFrom;
|
||||||
this.levelTo = levelTo;
|
this.levelTo = levelTo;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,33 +1,33 @@
|
||||||
/*
|
/*
|
||||||
* To change this license header, choose License Headers in Project Properties.
|
* To change this license header, choose License Headers in Project Properties.
|
||||||
* To change this template file, choose Tools | Templates
|
* To change this template file, choose Tools | Templates
|
||||||
* and open the template in the editor.
|
* and open the template in the editor.
|
||||||
*/
|
*/
|
||||||
package org.mage.card.arcane;
|
package org.mage.card.arcane;
|
||||||
|
|
||||||
import java.text.AttributedString;
|
import java.util.List;
|
||||||
import java.util.List;
|
|
||||||
|
/**
|
||||||
/**
|
* @author StravantUser
|
||||||
* @author StravantUser
|
*/
|
||||||
*/
|
public class TextboxLoyaltyRule extends TextboxRule {
|
||||||
public class TextboxLoyaltyRule extends TextboxRule {
|
|
||||||
public int loyaltyChange;
|
public int loyaltyChange;
|
||||||
|
|
||||||
public static int MINUS_X = 100;
|
public static int MINUS_X = 100;
|
||||||
|
|
||||||
public String getChangeString() {
|
public String getChangeString() {
|
||||||
if (loyaltyChange == MINUS_X) {
|
if (loyaltyChange == MINUS_X) {
|
||||||
return "-X";
|
return "-X";
|
||||||
} else if (loyaltyChange > 0) {
|
} else if (loyaltyChange > 0) {
|
||||||
return "+" + loyaltyChange;
|
return "+" + loyaltyChange;
|
||||||
} else {
|
} else {
|
||||||
return "" + loyaltyChange;
|
return "" + loyaltyChange;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public TextboxLoyaltyRule(String text, List<AttributeRegion> regions, int loyaltyChange) {
|
public TextboxLoyaltyRule(String text, List<AttributeRegion> regions, int loyaltyChange) {
|
||||||
super(text, regions, TextboxRuleType.LOYALTY);
|
super(text, regions, TextboxRuleType.LOYALTY);
|
||||||
this.loyaltyChange = loyaltyChange;
|
this.loyaltyChange = loyaltyChange;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,94 +1,98 @@
|
||||||
/*
|
/*
|
||||||
* To change this license header, choose License Headers in Project Properties.
|
* To change this license header, choose License Headers in Project Properties.
|
||||||
* To change this template file, choose Tools | Templates
|
* To change this template file, choose Tools | Templates
|
||||||
* and open the template in the editor.
|
* and open the template in the editor.
|
||||||
*/
|
*/
|
||||||
package org.mage.card.arcane;
|
package org.mage.card.arcane;
|
||||||
|
|
||||||
import java.awt.Font;
|
import java.awt.Font;
|
||||||
import java.awt.Image;
|
import java.awt.Image;
|
||||||
import java.awt.font.GraphicAttribute;
|
import java.awt.font.GraphicAttribute;
|
||||||
import java.awt.font.ImageGraphicAttribute;
|
import java.awt.font.ImageGraphicAttribute;
|
||||||
import java.awt.font.TextAttribute;
|
import java.awt.font.TextAttribute;
|
||||||
import java.text.AttributedString;
|
import java.text.AttributedString;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author stravant@gmail.com
|
* @author stravant@gmail.com
|
||||||
*
|
*
|
||||||
* Class describing parsed & translated rules in the text box of a card,
|
* Class describing parsed & translated rules in the text box of a card, ready
|
||||||
* ready to be rendered.
|
* to be rendered.
|
||||||
*/
|
*/
|
||||||
public class TextboxRule {
|
public class TextboxRule {
|
||||||
// An attributed region in the text, which can be applied to an
|
|
||||||
// attributed string.
|
// An attributed region in the text, which can be applied to an
|
||||||
public interface AttributeRegion {
|
// attributed string.
|
||||||
public void applyToAttributedString(AttributedString str, Font normal, Font italic);
|
public interface AttributeRegion {
|
||||||
}
|
|
||||||
|
public void applyToAttributedString(AttributedString str, Font normal, Font italic);
|
||||||
// A region of italics, or bold text in a
|
}
|
||||||
public static class ItalicRegion implements AttributeRegion {
|
|
||||||
ItalicRegion(int start, int end) {
|
// A region of italics, or bold text in a
|
||||||
this.start = start;
|
public static class ItalicRegion implements AttributeRegion {
|
||||||
this.end = end;
|
|
||||||
}
|
ItalicRegion(int start, int end) {
|
||||||
private final int start;
|
this.start = start;
|
||||||
private final int end;
|
this.end = end;
|
||||||
|
}
|
||||||
@Override
|
private final int start;
|
||||||
public void applyToAttributedString(AttributedString str, Font normal, Font italic) {
|
private final int end;
|
||||||
if (end > start+1) {
|
|
||||||
str.addAttribute(TextAttribute.FONT, italic, start, end);
|
@Override
|
||||||
}
|
public void applyToAttributedString(AttributedString str, Font normal, Font italic) {
|
||||||
}
|
if (end > start + 1) {
|
||||||
}
|
str.addAttribute(TextAttribute.FONT, italic, start, end);
|
||||||
|
}
|
||||||
// A special symbol embedded at some point in a string
|
}
|
||||||
public static class EmbeddedSymbol implements AttributeRegion {
|
}
|
||||||
EmbeddedSymbol(String symbol, int location) {
|
|
||||||
this.symbol = symbol;
|
// A special symbol embedded at some point in a string
|
||||||
this.location = location;
|
public static class EmbeddedSymbol implements AttributeRegion {
|
||||||
}
|
|
||||||
private final String symbol;
|
EmbeddedSymbol(String symbol, int location) {
|
||||||
private final int location;
|
this.symbol = symbol;
|
||||||
|
this.location = location;
|
||||||
@Override
|
}
|
||||||
public void applyToAttributedString(AttributedString str, Font normal, Font italic) {
|
private final String symbol;
|
||||||
Image symbolImage = ManaSymbols.getSizedManaSymbol(symbol, normal.getSize());
|
private final int location;
|
||||||
if (symbolImage != null) {
|
|
||||||
ImageGraphicAttribute imgAttr =
|
@Override
|
||||||
new ImageGraphicAttribute(symbolImage, GraphicAttribute.BOTTOM_ALIGNMENT);
|
public void applyToAttributedString(AttributedString str, Font normal, Font italic) {
|
||||||
str.addAttribute(TextAttribute.CHAR_REPLACEMENT, imgAttr, location, location+1);
|
Image symbolImage = ManaSymbols.getSizedManaSymbol(symbol.replace("/", ""), normal.getSize());
|
||||||
}
|
if (symbolImage != null) {
|
||||||
}
|
ImageGraphicAttribute imgAttr
|
||||||
}
|
= new ImageGraphicAttribute(symbolImage, GraphicAttribute.BOTTOM_ALIGNMENT);
|
||||||
|
str.addAttribute(TextAttribute.CHAR_REPLACEMENT, imgAttr, location, location + 1);
|
||||||
public String text;
|
}
|
||||||
public TextboxRuleType type;
|
}
|
||||||
|
}
|
||||||
private List<AttributeRegion> regions;
|
|
||||||
|
public String text;
|
||||||
protected TextboxRule(String text, List<AttributeRegion> regions, TextboxRuleType type) {
|
public TextboxRuleType type;
|
||||||
this.text = text;
|
|
||||||
this.type = type;
|
private List<AttributeRegion> regions;
|
||||||
this.regions = regions;
|
|
||||||
}
|
protected TextboxRule(String text, List<AttributeRegion> regions, TextboxRuleType type) {
|
||||||
|
this.text = text;
|
||||||
public TextboxRule(String text, List<AttributeRegion> regions) {
|
this.type = type;
|
||||||
this(text, regions, TextboxRuleType.NORMAL);
|
this.regions = regions;
|
||||||
}
|
}
|
||||||
|
|
||||||
public AttributedString generateAttributedString(Font normal, Font italic) {
|
public TextboxRule(String text, List<AttributeRegion> regions) {
|
||||||
// Build the final attributed text using the regions
|
this(text, regions, TextboxRuleType.NORMAL);
|
||||||
// Do it in reverse order for proper handling of regions where
|
}
|
||||||
// there are multiple attributes stacked (EG: bold + italic)
|
|
||||||
AttributedString attributedRule = new AttributedString(text);
|
public AttributedString generateAttributedString(Font normal, Font italic) {
|
||||||
if (text.length() != 0) {
|
// Build the final attributed text using the regions
|
||||||
attributedRule.addAttribute(TextAttribute.FONT, normal);
|
// Do it in reverse order for proper handling of regions where
|
||||||
for (int i = regions.size()-1; i >= 0; --i) {
|
// there are multiple attributes stacked (EG: bold + italic)
|
||||||
regions.get(i).applyToAttributedString(attributedRule, normal, italic);
|
AttributedString attributedRule = new AttributedString(text);
|
||||||
}
|
if (text.length() != 0) {
|
||||||
}
|
attributedRule.addAttribute(TextAttribute.FONT, normal);
|
||||||
return attributedRule;
|
for (int i = regions.size() - 1; i >= 0; --i) {
|
||||||
}
|
regions.get(i).applyToAttributedString(attributedRule, normal, italic);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
return attributedRule;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,251 +1,251 @@
|
||||||
/*
|
/*
|
||||||
* To change this license header, choose License Headers in Project Properties.
|
* To change this license header, choose License Headers in Project Properties.
|
||||||
* To change this template file, choose Tools | Templates
|
* To change this template file, choose Tools | Templates
|
||||||
* and open the template in the editor.
|
* and open the template in the editor.
|
||||||
*/
|
*/
|
||||||
package org.mage.card.arcane;
|
package org.mage.card.arcane;
|
||||||
|
|
||||||
import java.awt.Font;
|
import java.awt.Image;
|
||||||
import java.awt.Image;
|
import java.util.ArrayDeque;
|
||||||
import java.awt.font.GraphicAttribute;
|
import java.util.ArrayList;
|
||||||
import java.awt.font.ImageGraphicAttribute;
|
import java.util.Deque;
|
||||||
import java.awt.font.TextAttribute;
|
import java.util.regex.Matcher;
|
||||||
import java.text.AttributedString;
|
import java.util.regex.Pattern;
|
||||||
import java.util.ArrayDeque;
|
import mage.view.CardView;
|
||||||
import java.util.ArrayList;
|
import org.apache.log4j.Logger;
|
||||||
import java.util.Deque;
|
|
||||||
import java.util.List;
|
/**
|
||||||
import java.util.regex.Matcher;
|
*
|
||||||
import java.util.regex.Pattern;
|
* @author StravantUser
|
||||||
import mage.client.dialog.PreferencesDialog;
|
*/
|
||||||
import mage.view.CardView;
|
public class TextboxRuleParser {
|
||||||
import org.apache.log4j.Logger;
|
|
||||||
|
private static final Logger LOGGER = Logger.getLogger(CardPanel.class);
|
||||||
/**
|
|
||||||
*
|
private static final Pattern LevelAbilityPattern = Pattern.compile("Level (\\d+)-?(\\d*)(\\+?)");
|
||||||
* @author StravantUser
|
private static final Pattern LoyaltyAbilityPattern = Pattern.compile("^(\\+|\\-)(\\d+|X): ");
|
||||||
*/
|
private static final Pattern SimpleKeywordPattern = Pattern.compile("^(\\w+( \\w+)?)\\s*(\\([^\\)]*\\))?\\s*$");
|
||||||
public class TextboxRuleParser {
|
|
||||||
private static final Logger LOGGER = Logger.getLogger(CardPanel.class);
|
// Parse a given rule (given as a string) into a TextboxRule, replacing
|
||||||
|
// symbol annotations, italics, etc, parsing out information such as
|
||||||
private static final Pattern LevelAbilityPattern = Pattern.compile("Level (\\d+)-?(\\d*)(\\+?)");
|
// if the ability is a loyalty ability, and returning an TextboxRule
|
||||||
private static final Pattern LoyaltyAbilityPattern = Pattern.compile("^(\\+|\\-)(\\d+|X): ");
|
// representing that information, which can be used to render the rule in
|
||||||
private static final Pattern SimpleKeywordPattern = Pattern.compile("^(\\w+( \\w+)?)\\s*(\\([^\\)]*\\))?\\s*$");
|
// the textbox of a card.
|
||||||
|
public static TextboxRule parse(CardView source, String rule) {
|
||||||
// Parse a given rule (given as a string) into a TextboxRule, replacing
|
// List of regions to apply
|
||||||
// symbol annotations, italics, etc, parsing out information such as
|
ArrayList<TextboxRule.AttributeRegion> regions = new ArrayList<>();
|
||||||
// if the ability is a loyalty ability, and returning an TextboxRule
|
|
||||||
// representing that information, which can be used to render the rule in
|
// Leveler / loyalty
|
||||||
// the textbox of a card.
|
boolean isLeveler = false;
|
||||||
public static TextboxRule parse(CardView source, String rule) {
|
int levelFrom = 0;
|
||||||
// List of regions to apply
|
int levelTo = 0;
|
||||||
ArrayList<TextboxRule.AttributeRegion> regions = new ArrayList<>();
|
|
||||||
|
boolean isLoyalty = false;
|
||||||
// Leveler / loyalty
|
int loyaltyChange = 0;
|
||||||
boolean isLeveler = false;
|
|
||||||
int levelFrom = 0;
|
// Parse the attributedString contents
|
||||||
int levelTo = 0;
|
int index = 0;
|
||||||
|
int outputIndex = 0;
|
||||||
boolean isLoyalty = false;
|
|
||||||
int loyaltyChange = 0;
|
// Is it a simple keyword ability?
|
||||||
|
{
|
||||||
// Parse the attributedString contents
|
Matcher simpleKeywordMatch = SimpleKeywordPattern.matcher(rule);
|
||||||
int index = 0;
|
if (simpleKeywordMatch.find()) {
|
||||||
int outputIndex = 0;
|
return new TextboxKeywordRule(simpleKeywordMatch.group(1), regions);
|
||||||
|
}
|
||||||
// Is it a simple keyword ability?
|
}
|
||||||
{
|
|
||||||
Matcher simpleKeywordMatch = SimpleKeywordPattern.matcher(rule);
|
// Check if it's a loyalty ability. Must be right at the start of the rule
|
||||||
if (simpleKeywordMatch.find()) {
|
{
|
||||||
return new TextboxKeywordRule(simpleKeywordMatch.group(1), regions);
|
Matcher loyaltyMatch = LoyaltyAbilityPattern.matcher(rule);
|
||||||
}
|
if (loyaltyMatch.find()) {
|
||||||
}
|
// Get the loyalty change
|
||||||
|
if (loyaltyMatch.group(2).equals("X")) {
|
||||||
// Check if it's a loyalty ability. Must be right at the start of the rule
|
loyaltyChange = TextboxLoyaltyRule.MINUS_X;
|
||||||
{
|
} else {
|
||||||
Matcher loyaltyMatch = LoyaltyAbilityPattern.matcher(rule);
|
loyaltyChange = Integer.parseInt(loyaltyMatch.group(2));
|
||||||
if (loyaltyMatch.find()) {
|
if (loyaltyMatch.group(1).equals("-")) {
|
||||||
// Get the loyalty change
|
loyaltyChange = -loyaltyChange;
|
||||||
if (loyaltyMatch.group(2).equals("X")) {
|
}
|
||||||
loyaltyChange = TextboxLoyaltyRule.MINUS_X;
|
}
|
||||||
} else {
|
isLoyalty = true;
|
||||||
loyaltyChange = Integer.parseInt(loyaltyMatch.group(2));
|
|
||||||
if (loyaltyMatch.group(1).equals("-")) {
|
// Go past the match
|
||||||
loyaltyChange = -loyaltyChange;
|
index = loyaltyMatch.group().length();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
isLoyalty = true;
|
|
||||||
|
Deque<Integer> openingStack = new ArrayDeque<>();
|
||||||
// Go past the match
|
StringBuilder build = new StringBuilder();
|
||||||
index = loyaltyMatch.group().length();
|
while (index < rule.length()) {
|
||||||
}
|
int initialIndex = index;
|
||||||
}
|
char ch = rule.charAt(index);
|
||||||
|
switch (ch) {
|
||||||
Deque<Integer> openingStack = new ArrayDeque<>();
|
case '{': {
|
||||||
StringBuilder build = new StringBuilder();
|
// Handling for `{this}`
|
||||||
while (index < rule.length()) {
|
int closeIndex = rule.indexOf('}', index);
|
||||||
int initialIndex = index;
|
if (closeIndex == -1) {
|
||||||
char ch = rule.charAt(index);
|
// Malformed input, nothing to do
|
||||||
if (ch == '{') {
|
++index;
|
||||||
// Handling for `{this}`
|
++outputIndex;
|
||||||
int closeIndex = rule.indexOf('}', index);
|
build.append(ch);
|
||||||
if (closeIndex == -1) {
|
} else {
|
||||||
// Malformed input, nothing to do
|
String contents = rule.substring(index + 1, closeIndex);
|
||||||
++index;
|
if (contents.equals("this") || contents.equals("source")) {
|
||||||
++outputIndex;
|
// Replace {this} with the card's name
|
||||||
build.append(ch);
|
String cardName = source.getName();
|
||||||
} else {
|
build.append(cardName);
|
||||||
String contents = rule.substring(index+1, closeIndex);
|
index += contents.length() + 2;
|
||||||
if (contents.equals("this") || contents.equals("source")) {
|
outputIndex += cardName.length();
|
||||||
// Replace {this} with the card's name
|
} else {
|
||||||
String cardName = source.getName();
|
Image symbol = ManaSymbols.getSizedManaSymbol(contents.replace("/", ""), 10);
|
||||||
build.append(cardName);
|
if (symbol != null) {
|
||||||
index += contents.length() + 2;
|
// Mana or other inline symbol
|
||||||
outputIndex += cardName.length();
|
build.append('#');
|
||||||
} else {
|
regions.add(new TextboxRule.EmbeddedSymbol(contents, outputIndex));
|
||||||
Image symbol = ManaSymbols.getSizedManaSymbol(contents, 10);
|
++outputIndex;
|
||||||
if (symbol != null) {
|
index = closeIndex + 1;
|
||||||
// Mana or other inline symbol
|
} else {
|
||||||
build.append('#');
|
// Bad entry
|
||||||
regions.add(new TextboxRule.EmbeddedSymbol(contents, outputIndex));
|
build.append('{');
|
||||||
++outputIndex;
|
build.append(contents);
|
||||||
index = closeIndex+1;
|
build.append('}');
|
||||||
} else {
|
index = closeIndex + 1;
|
||||||
// Bad entry
|
outputIndex += (contents.length() + 2);
|
||||||
build.append('{');
|
}
|
||||||
build.append(contents);
|
}
|
||||||
build.append('}');
|
}
|
||||||
index = closeIndex+1;
|
break;
|
||||||
outputIndex += (contents.length() + 2);
|
}
|
||||||
}
|
case '&':
|
||||||
}
|
// Handling for `—`
|
||||||
}
|
if (rule.startsWith("—", index)) {
|
||||||
|
build.append('—');
|
||||||
} else if (ch == '&') {
|
index += 7;
|
||||||
// Handling for `—`
|
++outputIndex;
|
||||||
if (rule.startsWith("—", index)) {
|
} else if (rule.startsWith("&bull", index)) {
|
||||||
build.append('—');
|
build.append('•');
|
||||||
index += 7;
|
index += 5;
|
||||||
++outputIndex;
|
++outputIndex;
|
||||||
} else if (rule.startsWith("&bull", index)) {
|
} else {
|
||||||
build.append('•');
|
LOGGER.error("Bad &...; sequence `" + rule.substring(index + 1, index + 10) + "` in rule.");
|
||||||
index += 5;
|
build.append('&');
|
||||||
++outputIndex;
|
++index;
|
||||||
} else {
|
++outputIndex;
|
||||||
LOGGER.error("Bad &...; sequence `" + rule.substring(index+1, index+10) + "` in rule.");
|
}
|
||||||
build.append('&');
|
break;
|
||||||
++index;
|
case '<': {
|
||||||
++outputIndex;
|
// Handling for `<i>` and `<br/>`
|
||||||
}
|
int closeIndex = rule.indexOf('>', index);
|
||||||
|
if (closeIndex != -1) {
|
||||||
|
// Is a tag
|
||||||
} else if (ch == '<') {
|
String tag = rule.substring(index + 1, closeIndex);
|
||||||
// Handling for `<i>` and `<br/>`
|
if (tag.charAt(tag.length() - 1) == '/') {
|
||||||
int closeIndex = rule.indexOf('>', index);
|
// Pure closing tag (like <br/>)
|
||||||
if (closeIndex != -1) {
|
if (tag.equals("br/")) {
|
||||||
// Is a tag
|
build.append('\n');
|
||||||
String tag = rule.substring(index+1, closeIndex);
|
++outputIndex;
|
||||||
if (tag.charAt(tag.length()-1) == '/') {
|
} else {
|
||||||
// Pure closing tag (like <br/>)
|
// Unknown
|
||||||
if (tag.equals("br/")) {
|
build.append('<').append(tag).append('>');
|
||||||
build.append('\n');
|
outputIndex += (tag.length() + 2);
|
||||||
++outputIndex;
|
}
|
||||||
} else {
|
} else if (tag.charAt(0) == '/') {
|
||||||
// Unknown
|
// Opening index for the tag
|
||||||
build.append('<').append(tag).append('>');
|
int openingIndex;
|
||||||
outputIndex += (tag.length() + 2);
|
if (openingStack.isEmpty()) {
|
||||||
}
|
// Malformed input, just make an empty interval
|
||||||
} else if (tag.charAt(0) == '/') {
|
openingIndex = outputIndex;
|
||||||
// Opening index for the tag
|
} else {
|
||||||
int openingIndex;
|
openingIndex = openingStack.pop();
|
||||||
if (openingStack.isEmpty()) {
|
}
|
||||||
// Malformed input, just make an empty interval
|
|
||||||
openingIndex = outputIndex;
|
// What tag is it?
|
||||||
} else {
|
switch (tag) {
|
||||||
openingIndex = openingStack.pop();
|
case "/i":
|
||||||
}
|
// Italics
|
||||||
|
regions.add(new TextboxRule.ItalicRegion(openingIndex, outputIndex));
|
||||||
// What tag is it?
|
break;
|
||||||
if (tag.equals("/i")) {
|
case "/b":
|
||||||
// Italics
|
// Bold, see if it's a level ability
|
||||||
regions.add(new TextboxRule.ItalicRegion(openingIndex, outputIndex));
|
String content = build.substring(openingIndex);
|
||||||
} else if (tag.equals("/b")) {
|
Matcher levelMatch = LevelAbilityPattern.matcher(content);
|
||||||
// Bold, see if it's a level ability
|
if (levelMatch.find()) {
|
||||||
String content = build.substring(openingIndex);
|
try {
|
||||||
|
levelFrom = Integer.parseInt(levelMatch.group(1));
|
||||||
Matcher levelMatch = LevelAbilityPattern.matcher(content);
|
if (!levelMatch.group(2).equals("")) {
|
||||||
if (levelMatch.find()) {
|
levelTo = Integer.parseInt(levelMatch.group(2));
|
||||||
try {
|
}
|
||||||
levelFrom = Integer.parseInt(levelMatch.group(1));
|
if (!levelMatch.group(3).equals("")) {
|
||||||
if (!levelMatch.group(2).equals("")) {
|
levelTo = TextboxLevelRule.AND_HIGHER;
|
||||||
levelTo = Integer.parseInt(levelMatch.group(2));
|
}
|
||||||
}
|
isLeveler = true;
|
||||||
if (!levelMatch.group(3).equals("")) {
|
} catch (Exception e) {
|
||||||
levelTo = TextboxLevelRule.AND_HIGHER;
|
LOGGER.error("Bad leveler levels in rule `" + rule + "`.");
|
||||||
}
|
}
|
||||||
isLeveler = true;
|
}
|
||||||
} catch (Exception e) {
|
break;
|
||||||
LOGGER.error("Bad leveler levels in rule `" + rule + "`.");
|
default:
|
||||||
}
|
// Unknown
|
||||||
}
|
build.append('<').append(tag).append('>');
|
||||||
} else {
|
outputIndex += (tag.length() + 2);
|
||||||
// Unknown
|
break;
|
||||||
build.append('<').append(tag).append('>');
|
}
|
||||||
outputIndex += (tag.length() + 2);
|
} else // Is it a <br> tag special case? [Why can't it have a closing `/`... =( ]
|
||||||
}
|
{
|
||||||
} else {
|
if (tag.equals("br")) {
|
||||||
// Is it a <br> tag special case? [Why can't it have a closing `/`... =( ]
|
build.append('\n');
|
||||||
if (tag.equals("br")) {
|
++outputIndex;
|
||||||
build.append('\n');
|
} else {
|
||||||
++outputIndex;
|
// Opening tag
|
||||||
} else {
|
openingStack.push(outputIndex);
|
||||||
// Opening tag
|
}
|
||||||
openingStack.push(outputIndex);
|
}
|
||||||
}
|
// Skip characters
|
||||||
}
|
index = closeIndex + 1;
|
||||||
// Skip characters
|
} else {
|
||||||
index = closeIndex+1;
|
// Malformed tag
|
||||||
} else {
|
build.append('<');
|
||||||
// Malformed tag
|
++outputIndex;
|
||||||
build.append('<');
|
++index;
|
||||||
++outputIndex;
|
}
|
||||||
++index;
|
break;
|
||||||
}
|
}
|
||||||
|
default:
|
||||||
} else {
|
// Normal character
|
||||||
// Normal character
|
++index;
|
||||||
++index;
|
++outputIndex;
|
||||||
++outputIndex;
|
build.append(ch);
|
||||||
build.append(ch);
|
break;
|
||||||
}
|
}
|
||||||
if (outputIndex != build.length()) {
|
if (outputIndex != build.length()) {
|
||||||
// Somehow our parsing code output symbols but didn't update the output index correspondingly
|
// Somehow our parsing code output symbols but didn't update the output index correspondingly
|
||||||
LOGGER.error("The human is dead; mismatch! Failed on rule: `" + rule + "` due to not updating outputIndex properly.");
|
LOGGER.error("The human is dead; mismatch! Failed on rule: `" + rule + "` due to not updating outputIndex properly.");
|
||||||
|
|
||||||
// Bail out
|
// Bail out
|
||||||
build = new StringBuilder(rule);
|
build = new StringBuilder(rule);
|
||||||
regions.clear();
|
regions.clear();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (index == initialIndex) {
|
if (index == initialIndex) {
|
||||||
// Somehow our parsing failed to consume the
|
// Somehow our parsing failed to consume the
|
||||||
LOGGER.error("Failed on rule `" + rule + "` due to not consuming a character.");
|
LOGGER.error("Failed on rule `" + rule + "` due to not consuming a character.");
|
||||||
|
|
||||||
// Bail out
|
// Bail out
|
||||||
build = new StringBuilder(rule);
|
build = new StringBuilder(rule);
|
||||||
regions.clear();
|
regions.clear();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Build and return the rule
|
// Build and return the rule
|
||||||
rule = build.toString();
|
rule = build.toString();
|
||||||
if (isLoyalty) {
|
if (isLoyalty) {
|
||||||
return new TextboxLoyaltyRule(rule, regions, loyaltyChange);
|
return new TextboxLoyaltyRule(rule, regions, loyaltyChange);
|
||||||
} else if (isLeveler) {
|
} else if (isLeveler) {
|
||||||
return new TextboxLevelRule(rule, regions, levelFrom, levelTo);
|
return new TextboxLevelRule(rule, regions, levelFrom, levelTo);
|
||||||
} else {
|
} else {
|
||||||
return new TextboxRule(rule, regions);
|
return new TextboxRule(rule, regions);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue