From 577bdaea8438e0544901cf2f1a8cf58e7cd73925 Mon Sep 17 00:00:00 2001 From: Mark Langen Date: Wed, 14 Sep 2016 19:32:53 -0600 Subject: [PATCH] Fixes and additions to card rendering * Vehicles are rendered with a vehicle background and changed P/T box color * Kaladesh Inventions are rendered with the invention frame * Kaladesh Inventions use the full-frame art if they detect that you have that full art downloaded instead of normal card images. * Changed land text-box colors to be a bit more saturated to make it clearer what colors they produce * Added mana symbol in the textbox of basic lands instead of rules text as long as they have no additional abilities. * Fixed problem with triggered abilities on the stack showing up with a type of "??? Ability". Not sure what the real cause is but those abilities have abilityType = null, just worked around it. --- .../org/mage/card/arcane/CardRenderer.java | 5 + .../mage/card/arcane/ModernCardRenderer.java | 201 ++++++++++++++---- .../card/arcane/TextboxBasicManaRule.java | 20 ++ .../mage/card/arcane/TextboxRuleParser.java | 17 +- .../org/mage/card/arcane/TextboxRuleType.java | 3 + .../cardrender/background_texture_vehicle.png | Bin 0 -> 685 bytes .../resources/cardrender/invention_frame.png | Bin 0 -> 30584 bytes .../sets/masterpieceseries/AEtherVial.java | 3 + .../CataclysmicGearhulk.java | 5 + .../sets/masterpieceseries/ChampionsHelm.java | 3 + .../masterpieceseries/ChromaticLantern.java | 3 + .../sets/masterpieceseries/ChromeMox.java | 3 + .../masterpieceseries/CloudstoneCurio.java | 3 + .../masterpieceseries/CrucibleOfWorlds.java | 3 + .../masterpieceseries/GauntletOfPower.java | 3 + .../masterpieceseries/HangarbackWalker.java | 3 + .../masterpieceseries/LightningGreaves.java | 3 + .../sets/masterpieceseries/LotusPetal.java | 3 + .../sets/masterpieceseries/ManaCrypt.java | 5 + .../sets/masterpieceseries/ManaVault.java | 3 + .../mage/sets/masterpieceseries/MindsEye.java | 3 + .../mage/sets/masterpieceseries/MoxOpal.java | 5 + .../masterpieceseries/PaintersServant.java | 3 + .../RingsOfBrighthearth.java | 3 + .../sets/masterpieceseries/ScrollRack.java | 3 + .../masterpieceseries/SculptingSteel.java | 3 + .../mage/sets/masterpieceseries/SolRing.java | 3 + .../masterpieceseries/SolemnSimulacrum.java | 3 + .../sets/masterpieceseries/StaticOrb.java | 3 + .../sets/masterpieceseries/SteelOverseer.java | 3 + .../SwordOfFeastAndFamine.java | 5 + .../masterpieceseries/SwordOfFireAndIce.java | 3 + .../SwordOfLightAndShadow.java | 3 + .../masterpieceseries/VerdurousGearhulk.java | 5 + Mage/src/main/java/mage/cards/FrameStyle.java | 5 + .../mage/cards/repository/CardRepository.java | 2 +- 36 files changed, 297 insertions(+), 47 deletions(-) create mode 100644 Mage.Client/src/main/java/org/mage/card/arcane/TextboxBasicManaRule.java create mode 100644 Mage.Client/src/main/resources/cardrender/background_texture_vehicle.png create mode 100644 Mage.Client/src/main/resources/cardrender/invention_frame.png diff --git a/Mage.Client/src/main/java/org/mage/card/arcane/CardRenderer.java b/Mage.Client/src/main/java/org/mage/card/arcane/CardRenderer.java index 53b6aa07419..3236c785957 100644 --- a/Mage.Client/src/main/java/org/mage/card/arcane/CardRenderer.java +++ b/Mage.Client/src/main/java/org/mage/card/arcane/CardRenderer.java @@ -14,6 +14,8 @@ import java.awt.Paint; import java.awt.Polygon; import java.awt.image.BufferedImage; import java.util.ArrayList; + +import mage.abilities.Ability; import mage.client.dialog.PreferencesDialog; import mage.constants.AbilityType; import mage.constants.CardType; @@ -345,6 +347,9 @@ public abstract class CardRenderer { return "Triggered Ability"; } else if (AbilityType.ACTIVATED.equals(cardView.getAbilityType())) { return "Activated Ability"; + } else if (cardView.getAbilityType() == null) { + // TODO: Triggered abilities waiting to be put onto the stack have abilityType = null. Figure out why + return "Triggered Ability"; } else { return "??? Ability"; } diff --git a/Mage.Client/src/main/java/org/mage/card/arcane/ModernCardRenderer.java b/Mage.Client/src/main/java/org/mage/card/arcane/ModernCardRenderer.java index e995f4d8174..bdfbb50ee85 100644 --- a/Mage.Client/src/main/java/org/mage/card/arcane/ModernCardRenderer.java +++ b/Mage.Client/src/main/java/org/mage/card/arcane/ModernCardRenderer.java @@ -5,16 +5,7 @@ */ package org.mage.card.arcane; -import java.awt.BasicStroke; -import java.awt.Color; -import java.awt.Font; -import java.awt.FontFormatException; -import java.awt.Graphics2D; -import java.awt.LinearGradientPaint; -import java.awt.Paint; -import java.awt.Polygon; -import java.awt.Rectangle; -import java.awt.TexturePaint; +import java.awt.*; import java.awt.font.FontRenderContext; import java.awt.font.LineBreakMeasurer; import java.awt.font.TextAttribute; @@ -32,7 +23,9 @@ import java.util.ArrayList; import java.util.Collection; import java.util.List; import javax.swing.ImageIcon; + import mage.ObjectColor; +import mage.cards.FrameStyle; import mage.client.dialog.PreferencesDialog; import mage.constants.CardType; import mage.view.CardView; @@ -77,6 +70,12 @@ public class ModernCardRenderer extends CardRenderer { return new TexturePaint(img, new Rectangle(0, 0, img.getWidth(), img.getHeight())); } + private static BufferedImage loadFramePart(String name) { + URL url = ModernCardRenderer.class.getResource("/cardrender/" + name + ".png"); + ImageIcon icon = new ImageIcon(url); + return CardRendererUtils.toBufferedImage(icon.getImage()); + } + private static Font loadFont(String name) { try { return Font.createFont( @@ -99,6 +98,9 @@ public class ModernCardRenderer extends CardRenderer { public static Paint BG_TEXTURE_GOLD = loadBackgroundTexture("gold"); public static Paint BG_TEXTURE_ARTIFACT = loadBackgroundTexture("artifact"); public static Paint BG_TEXTURE_LAND = loadBackgroundTexture("land"); + public static Paint BG_TEXTURE_VEHICLE = loadBackgroundTexture("vehicle"); + + public static BufferedImage FRAME_INVENTION = loadFramePart("invention_frame"); public static Color BORDER_WHITE = new Color(216, 203, 188); public static Color BORDER_BLUE = new Color(20, 121, 175); @@ -117,6 +119,8 @@ public class ModernCardRenderer extends CardRenderer { public static Color BOX_GOLD = new Color(223, 195, 136); public static Color BOX_COLORLESS = new Color(220, 228, 232); public static Color BOX_LAND = new Color(220, 215, 213); + public static Color BOX_INVENTION = new Color(209, 97, 33); + public static Color BOX_VEHICLE = new Color(155, 105, 60); public static Color BOX_WHITE_NIGHT = new Color(169, 160, 145); public static Color BOX_BLUE_NIGHT = new Color(46, 133, 176); @@ -126,6 +130,13 @@ public class ModernCardRenderer extends CardRenderer { public static Color BOX_GOLD_NIGHT = new Color(171, 134, 70); public static Color BOX_COLORLESS_NIGHT = new Color(118, 147, 158); + public static Color LAND_TEXTBOX_WHITE = new Color(248, 232, 188, 244); + public static Color LAND_TEXTBOX_BLUE = new Color(189, 212, 236, 244); + public static Color LAND_TEXTBOX_BLACK = new Color(174, 164, 162, 244); + public static Color LAND_TEXTBOX_RED = new Color(242, 168, 133, 244); + public static Color LAND_TEXTBOX_GREEN = new Color(198, 220, 198, 244); + public static Color LAND_TEXTBOX_GOLD = new Color(236, 229, 207, 244); + public static Color TEXTBOX_WHITE = new Color(252, 249, 244, 244); public static Color TEXTBOX_BLUE = new Color(229, 238, 247, 244); public static Color TEXTBOX_BLACK = new Color(241, 241, 240, 244); @@ -272,7 +283,7 @@ public class ModernCardRenderer extends CardRenderer { drawCardBack(g); } else { // Set texture to paint with - g.setPaint(getBackgroundPaint(cardView.getColor(), cardView.getCardTypes())); + g.setPaint(getBackgroundPaint(cardView.getColor(), cardView.getCardTypes(), cardView.getSubTypes())); // Draw main part (most of card) g.fillRoundRect( @@ -299,7 +310,9 @@ public class ModernCardRenderer extends CardRenderer { */ private Rectangle2D getArtRect() { Rectangle2D rect; - if (cardView.getFrameStyle().isFullArt() || cardView.isToken()) { + if (useInventionFrame()) { + rect = new Rectangle2D.Float(0, 0, 1, 1); + } else if (cardView.getFrameStyle().isFullArt() || cardView.isToken()) { rect = new Rectangle2D.Float(.079f, .11f, .84f, .63f); } else { rect = new Rectangle2D.Float(.079f, .11f, .84f, .42f); @@ -317,6 +330,23 @@ public class ModernCardRenderer extends CardRenderer { } } + protected boolean isSourceArtFullArt() { + int color = artImage.getRGB(0, artImage.getHeight() / 2); + return (((color & 0x00FF0000) > 0x00200000) || + ((color & 0x0000FF00) > 0x00002000) || + ((color & 0x000000FF) > 0x00000020)); + } + + private boolean useInventionFrame() { + if (cardView.getFrameStyle() != FrameStyle.KLD_INVENTION) { + return false; + } else if (artImage == null) { + return true; + } else { + return isSourceArtFullArt(); + } + } + @Override protected void drawArt(Graphics2D g) { if (artImage != null && !cardView.isFaceDown()) { @@ -331,22 +361,33 @@ public class ModernCardRenderer extends CardRenderer { double targetWidth = contentWidth - 2; double targetHeight = typeLineY - totalContentInset - boxHeight; double targetAspect = targetWidth / targetHeight; - if (targetAspect * artHeight < artWidth) { - // Trim off some width - artWidth = targetAspect * artHeight; + if (useInventionFrame()) { + // No adjustment to art } else { - // Trim off some height - artHeight = artWidth / targetAspect; + if (targetAspect * artHeight < artWidth) { + // Trim off some width + artWidth = targetAspect * artHeight; + } else { + // Trim off some height + artHeight = artWidth / targetAspect; + } } try { BufferedImage subImg = artImage.getSubimage( (int) (artRect.getX() * fullCardImgWidth), (int) (artRect.getY() * fullCardImgHeight), (int) artWidth, (int) artHeight); - g.drawImage(subImg, - totalContentInset + 1, totalContentInset + boxHeight, - (int) targetWidth, (int) targetHeight, - null); + if (useInventionFrame()) { + g.drawImage(subImg, + borderWidth, borderWidth, + cardWidth - 2*borderWidth, cardHeight - 2*borderWidth, + null); + } else { + g.drawImage(subImg, + totalContentInset + 1, totalContentInset + boxHeight, + (int) targetWidth, (int) targetHeight, + null); + } } catch (RasterFormatException e) { // At very small card sizes we may encounter a problem with rounding error making the rect not fit } @@ -363,14 +404,30 @@ public class ModernCardRenderer extends CardRenderer { Paint textboxPaint = getTextboxPaint(frameColors, cardView.getCardTypes(), cardWidth); Paint borderPaint = getBorderPaint(frameColors, cardView.getCardTypes(), cardWidth); + // Special colors + if (cardView.getFrameStyle() == FrameStyle.KLD_INVENTION) { + boxColor = BOX_INVENTION; + } + // Draw the main card content border g.setPaint(borderPaint); - g.drawRect( - totalContentInset, totalContentInset, - contentWidth - 1, cardHeight - borderWidth * 3 - totalContentInset - 1); + if (cardView.getFrameStyle() == FrameStyle.KLD_INVENTION) { + g.drawImage(FRAME_INVENTION, 0, 0, cardWidth, cardHeight, null); + g.drawRect( + totalContentInset, typeLineY, + contentWidth - 1, cardHeight - borderWidth * 3 - typeLineY - 1); + } else { + g.drawRect( + totalContentInset, totalContentInset, + contentWidth - 1, cardHeight - borderWidth * 3 - totalContentInset - 1); + } // Draw the textbox fill - g.setPaint(textboxPaint); + if (useInventionFrame()) { + g.setPaint(new Color(255, 255, 255, 150)); + } else { + g.setPaint(textboxPaint); + } g.fillRect( totalContentInset + 1, typeLineY, contentWidth - 2, cardHeight - borderWidth * 3 - typeLineY - 1); @@ -383,16 +440,18 @@ public class ModernCardRenderer extends CardRenderer { cardWidth / 16, cardHeight - typeLineY - boxHeight - borderWidth * 3); } - // Draw a shadow highlight at the right edge of the content frame - g.setColor(new Color(0, 0, 0, 100)); - g.fillRect( - totalContentInset - 1, totalContentInset, - 1, cardHeight - borderWidth * 3 - totalContentInset - 1); + if (cardView.getFrameStyle() != FrameStyle.KLD_INVENTION) { + // Draw a shadow highlight at the right edge of the content frame + g.setColor(new Color(0, 0, 0, 100)); + g.fillRect( + totalContentInset - 1, totalContentInset, + 1, cardHeight - borderWidth * 3 - totalContentInset - 1); - // Draw a shadow highlight separating the card art and rest of frame - g.drawRect( - totalContentInset + 1, totalContentInset + boxHeight, - contentWidth - 3, typeLineY - totalContentInset - boxHeight - 1); + // Draw a shadow highlight separating the card art and rest of frame + g.drawRect( + totalContentInset + 1, totalContentInset + boxHeight, + contentWidth - 3, typeLineY - totalContentInset - boxHeight - 1); + } // Draw the name line box CardRendererUtils.drawRoundedBox(g, @@ -549,7 +608,8 @@ public class ModernCardRenderer extends CardRenderer { int partWidth = (int) Math.max(30, 0.20f * cardWidth); // Is it a creature? - if (cardView.getCardTypes().contains(CardType.CREATURE) || cardView.getSubTypes().contains("Vehicle")) { + boolean isVehicle = cardView.getSubTypes().contains("Vehicle"); + if (cardView.getCardTypes().contains(CardType.CREATURE) || isVehicle) { int x = cardWidth - borderWidth - partWidth; // Draw PT box @@ -558,7 +618,7 @@ public class ModernCardRenderer extends CardRenderer { partWidth, boxHeight, contentInset, borderPaint, - fill); + isVehicle ? BOX_VEHICLE : fill); // Draw shadow line top g.setColor(new Color(0, 0, 0, 150)); @@ -567,7 +627,7 @@ public class ModernCardRenderer extends CardRenderer { partWidth - 2 * contentInset, 1); // Draw text - g.setColor(getBoxTextColor()); + g.setColor(isVehicle ? Color.white : getBoxTextColor()); g.setFont(ptTextFont); String ptText = cardView.getPower() + "/" + cardView.getToughness(); int ptTextWidth = g.getFontMetrics().stringWidth(ptText); @@ -703,6 +763,12 @@ public class ModernCardRenderer extends CardRenderer { allRules.add(keywordsRule); } + // Basic mana draw mana symbol in textbox (for basic lands) + if (allRules.size() == 1 && allRules.get(0) instanceof TextboxBasicManaRule) { + drawBasicManaTextbox(g, x, y, w, h, ((TextboxBasicManaRule)allRules.get(0)).getBasicManaSymbol()); + return; + } + // Go through possible font sizes in descending order to find the best fit RuleLayout bestLayout = null; for (int fontSize: RULES_TEXT_FONT_SIZES) { @@ -745,6 +811,14 @@ public class ModernCardRenderer extends CardRenderer { } } + // Draw a basic mana symbol + private void drawBasicManaTextbox(Graphics2D g, int x, int y, int w, int h, String symbol) { + String symbs = symbol; + int symbHeight = (int)(0.8*h); + int manaCostWidth = CardRendererUtils.getManaCostWidth(symbs, symbHeight); + ManaSymbols.draw(g, symbs, x + (w - manaCostWidth)/2, y + (h - symbHeight)/2, symbHeight); + } + // Get the first line of the textbox, the keyword string private String getKeywordRulesString() { StringBuilder builder = new StringBuilder(); @@ -944,8 +1018,10 @@ public class ModernCardRenderer extends CardRenderer { // Determine which background paint to use from a set of colors // and the current card. - protected static Paint getBackgroundPaint(ObjectColor colors, Collection types) { - if (types.contains(CardType.LAND)) { + protected static Paint getBackgroundPaint(ObjectColor colors, Collection types, Collection subTypes) { + if (subTypes.contains("Vehicle")) { + return BG_TEXTURE_VEHICLE; + } else if (types.contains(CardType.LAND)) { return BG_TEXTURE_LAND; } else if (types.contains(CardType.ARTIFACT)) { return BG_TEXTURE_ARTIFACT; @@ -1074,22 +1150,53 @@ public class ModernCardRenderer extends CardRenderer { } } + // Determine the land textbox color for a single color. Uses the same colors as the + // type / name line. + protected static Color getLandTextboxColor(ObjectColor color) { + if (color.isWhite()) { + return LAND_TEXTBOX_WHITE; + } else if (color.isBlue()) { + return LAND_TEXTBOX_BLUE; + } else if (color.isBlack()) { + return LAND_TEXTBOX_BLACK; + } else if (color.isRed()) { + return LAND_TEXTBOX_RED; + } else if (color.isGreen()) { + return LAND_TEXTBOX_GREEN; + } else { + return ERROR_COLOR; + } + } + // Determine the border paint to use, based on an ObjectColors protected static Paint getTextboxPaint(ObjectColor colors, Collection types, int width) { if (colors.isMulticolored()) { if (colors.getColorCount() == 2) { List twoColors = colors.getColors(); + Color[] translatedColors; + if (types.contains(CardType.LAND)) { + translatedColors = new Color[]{ + getLandTextboxColor(twoColors.get(0)), + getLandTextboxColor(twoColors.get(1)) + }; + } else { + translatedColors = new Color[]{ + getTextboxColor(twoColors.get(0)), + getTextboxColor(twoColors.get(1)) + }; + } // Special case for two colors, gradient paint return new LinearGradientPaint( 0, 0, width, 0, new float[]{0.4f, 0.6f}, - new Color[]{ - getTextboxColor(twoColors.get(0)), - getTextboxColor(twoColors.get(1)) - }); + translatedColors); } else { - return TEXTBOX_GOLD; + if (types.contains(CardType.LAND)) { + return LAND_TEXTBOX_GOLD; + } else { + return TEXTBOX_GOLD; + } } } else if (colors.isColorless()) { if (types.contains(CardType.LAND)) { @@ -1098,7 +1205,11 @@ public class ModernCardRenderer extends CardRenderer { return TEXTBOX_COLORLESS; } } else { - return getTextboxColor(colors); + if (types.contains(CardType.LAND)) { + return getLandTextboxColor(colors); + } else { + return getTextboxColor(colors); + } } } } diff --git a/Mage.Client/src/main/java/org/mage/card/arcane/TextboxBasicManaRule.java b/Mage.Client/src/main/java/org/mage/card/arcane/TextboxBasicManaRule.java new file mode 100644 index 00000000000..8b68848566f --- /dev/null +++ b/Mage.Client/src/main/java/org/mage/card/arcane/TextboxBasicManaRule.java @@ -0,0 +1,20 @@ +package org.mage.card.arcane; + +import java.util.ArrayList; + +/** + * Created by stravant@gmail.com on 2016-09-14. + */ +public class TextboxBasicManaRule extends TextboxRule { + private String basicManaSymbol; + + public TextboxBasicManaRule(String rule, ArrayList regions, String basicManaSymbol) { + super(rule, regions, TextboxRuleType.BASIC_MANA); + + this.basicManaSymbol = basicManaSymbol; + } + + public String getBasicManaSymbol() { + return basicManaSymbol; + } +} diff --git a/Mage.Client/src/main/java/org/mage/card/arcane/TextboxRuleParser.java b/Mage.Client/src/main/java/org/mage/card/arcane/TextboxRuleParser.java index 021e150ad6b..4c380281a7c 100644 --- a/Mage.Client/src/main/java/org/mage/card/arcane/TextboxRuleParser.java +++ b/Mage.Client/src/main/java/org/mage/card/arcane/TextboxRuleParser.java @@ -22,6 +22,7 @@ public class TextboxRuleParser { private static final Logger LOGGER = Logger.getLogger(CardPanel.class); + private static final Pattern BasicManaAbility = Pattern.compile("\\{T\\}: Add \\{(\\w)\\} to your mana pool\\."); private static final Pattern LevelAbilityPattern = Pattern.compile("Level (\\d+)-?(\\d*)(\\+?)"); private static final Pattern LoyaltyAbilityPattern = Pattern.compile("^(\\+|\\-)(\\d+|X): "); private static final Pattern SimpleKeywordPattern = Pattern.compile("^(\\w+( \\w+)?)\\s*(\\([^\\)]*\\))?\\s*$"); @@ -35,7 +36,7 @@ public class TextboxRuleParser { // List of regions to apply ArrayList regions = new ArrayList<>(); - // Leveler / loyalty + // Leveler / loyalty / basic boolean isLeveler = false; int levelFrom = 0; int levelTo = 0; @@ -43,6 +44,9 @@ public class TextboxRuleParser { boolean isLoyalty = false; int loyaltyChange = 0; + boolean isBasicMana = false; + String basicManaSymbol = ""; + // Parse the attributedString contents int index = 0; int outputIndex = 0; @@ -55,6 +59,15 @@ public class TextboxRuleParser { } } + // Is it a basic mana ability? + { + Matcher basicManaMatcher = BasicManaAbility.matcher(rule); + if (basicManaMatcher.find()) { + isBasicMana = true; + basicManaSymbol = basicManaMatcher.group(1); + } + } + // Check if it's a loyalty ability. Must be right at the start of the rule { Matcher loyaltyMatch = LoyaltyAbilityPattern.matcher(rule); @@ -244,6 +257,8 @@ public class TextboxRuleParser { return new TextboxLoyaltyRule(rule, regions, loyaltyChange); } else if (isLeveler) { return new TextboxLevelRule(rule, regions, levelFrom, levelTo); + } else if (isBasicMana) { + return new TextboxBasicManaRule(rule, regions, basicManaSymbol); } else { return new TextboxRule(rule, regions); } diff --git a/Mage.Client/src/main/java/org/mage/card/arcane/TextboxRuleType.java b/Mage.Client/src/main/java/org/mage/card/arcane/TextboxRuleType.java index 4903130db44..76538a86a9a 100644 --- a/Mage.Client/src/main/java/org/mage/card/arcane/TextboxRuleType.java +++ b/Mage.Client/src/main/java/org/mage/card/arcane/TextboxRuleType.java @@ -19,6 +19,9 @@ public enum TextboxRuleType { /* Loyalty abilities on planeswalkers */ LOYALTY, + + /* Basic mana ability */ + BASIC_MANA, /* Levelup creature - static ability at a given level */ LEVEL diff --git a/Mage.Client/src/main/resources/cardrender/background_texture_vehicle.png b/Mage.Client/src/main/resources/cardrender/background_texture_vehicle.png new file mode 100644 index 0000000000000000000000000000000000000000..2f58f34a36174e2509d793d5414726fc8157be6b GIT binary patch literal 685 zcmV;e0#f~nP)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGi!vFvd!vV){sAK>D02y>eSaefwW^{L9 za%BK;VQFr3E^cLXAT%y8E-^5z3JSmg00JFJL_t(IPleN6Z_;2C2k_@R_zBeMD6mnW zAkKxL*_OFvnX}PE6Ae%ceWMJhzyP%b5a!~HWJoMyr7yhHsZkT-g%|Uq*`)KC$#b!* zbMni{|9^FW&iOUoXYwwM^A9MO#(KxxoFmg*&_;U)_Rs}y#qVI$Ob1_ugV8twIfq0barG1m^#Z}&~3GQ(&^k4Ov=mMdO1W;1$G3V0g>wSJ1 zRzq=mz(;D{WU%ApRW-8&tD#txm1!{wdNQTdlO1u>I4I1z)#2U_D&Xkkhhly1j9n8L=0+Pi#$x08{JSA0`aw}DCq5?MK=`BjwNU-EHKAx{V;_|2f?q%y>`jxJ~ zeNvEVd7qU#sDPVy*I&HvGOyZPt1quXun>t}n!mP^pxI`>-S5|4ze5G^yUkRk zDz^5e_6NDAG!HdY0A1b7Hr}wc23KyB4i&M}Lk0L_Wcbc~Vre~k``*UWbZk3;3fNl1 z$W;#+yYg@qi<9`{Z5$OaEc&OV8aAC}dT>vluJ{^=nCZJH5%6R_*vsaK> TK~^c800000NkvXXu0mjfRy;Ed literal 0 HcmV?d00001 diff --git a/Mage.Client/src/main/resources/cardrender/invention_frame.png b/Mage.Client/src/main/resources/cardrender/invention_frame.png new file mode 100644 index 0000000000000000000000000000000000000000..4940ef693279e79cc8f7c345085f8fc68fffb0c3 GIT binary patch literal 30584 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 n_ cardDao; private Set classNames;