diff --git a/Mage.Client/src/main/java/mage/client/dialog/TestCardRenderDialog.java b/Mage.Client/src/main/java/mage/client/dialog/TestCardRenderDialog.java index 7bf737f1946..414871e94c1 100644 --- a/Mage.Client/src/main/java/mage/client/dialog/TestCardRenderDialog.java +++ b/Mage.Client/src/main/java/mage/client/dialog/TestCardRenderDialog.java @@ -408,9 +408,26 @@ public class TestCardRenderDialog extends MageDialog { /* test split, transform and mdf in hands cardViews.add(createHandCard(game, playerYou.getId(), "SOI", "97")); // Accursed Witch - cardViews.add(createHandCard(game, playerYou.getId(), "UMA", "225")); // Fire // Ice - cardViews.add(createHandCard(game, playerYou.getId(), "ELD", "14")); // Giant Killer cardViews.add(createHandCard(game, playerYou.getId(), "ZNR", "134")); // Akoum Warrior + cardViews.add(createHandCard(game, playerYou.getId(), "UMA", "225")); // Fire // Ice + cardViews.add(createHandCard(game, playerYou.getId(), "DGM", "123")); // Beck // Call + cardViews.add(createHandCard(game, playerYou.getId(), "AKH", "210")); // Dusk // Dawn + //*/ + + //* test adventure cards in hands + cardViews.add(createHandCard(game, playerYou.getId(), "ELD", "14")); // Giant Killer + cardViews.add(createHandCard(game, playerYou.getId(), "WOE", "222")); // Cruel Somnophage + cardViews.add(createHandCard(game, playerYou.getId(), "WOE", "227")); // Gingerbread Hunter + cardViews.add(createHandCard(game, playerYou.getId(), "WOE", "221")); // Callous Sell-Sword + cardViews.add(createHandCard(game, playerYou.getId(), "ELD", "149")); // Beanstalk Giant + cardViews.add(createHandCard(game, playerYou.getId(), "WOE", "220")); // Beluna Grandsquall + //*/ + + /* test saga and case cards in hands + cardViews.add(createHandCard(game, playerYou.getId(), "DOM", "90")); // The Eldest Reborn + cardViews.add(createHandCard(game, playerYou.getId(), "MH2", "259")); // Urza's Saga + cardViews.add(createHandCard(game, playerYou.getId(), "MKM", "113")); // Case of the Burning Masks + cardViews.add(createHandCard(game, playerYou.getId(), "MKM", "155")); // Case of the Locked Hothouse //*/ /* test meld cards in hands and battlefield @@ -441,7 +458,7 @@ public class TestCardRenderDialog extends MageDialog { //cardViews.add(createPermanentCard(game, playerYou.getId(), "KHM", "50", 1, 1, 0, true, false, additionalIcons)); // Cosima, God of the Voyage //*/ - //* test tokens + /* test tokens // normal cardViews.add(createToken(game, playerYou.getId(), new ZombieToken(), "10E", 0, false, false)); cardViews.add(createToken(game, playerYou.getId(), new ZombieToken(), "XXX", 1, false, false)); @@ -826,7 +843,7 @@ public class TestCardRenderDialog extends MageDialog { }//GEN-LAST:event_comboRenderModeItemStateChanged private void sliderSizeStateChanged(javax.swing.event.ChangeEvent evt) {//GEN-FIRST:event_sliderSizeStateChanged - // from DragCardGrid + // from DragCardGrid // Fraction in [-1, 1] float sliderFrac = ((float) (sliderSize.getValue() - 50)) / 50; // Convert to frac in [0.5, 2.0] exponentially 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 8d8b521ccad..3067b5a2656 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 @@ -106,8 +106,8 @@ public abstract class CardRenderer { protected int borderWidth; // The parsed text of the card - protected final ArrayList textboxRules = new ArrayList<>(); - protected final ArrayList textboxKeywords = new ArrayList<>(); + protected ArrayList textboxRules = new ArrayList<>(); + protected ArrayList textboxKeywords = new ArrayList<>(); // The Construtor // The constructor should prepare all of the things that it can diff --git a/Mage.Client/src/main/java/org/mage/card/arcane/CardRendererFactory.java b/Mage.Client/src/main/java/org/mage/card/arcane/CardRendererFactory.java index 0c206ee8aee..3d3f9c2e811 100644 --- a/Mage.Client/src/main/java/org/mage/card/arcane/CardRendererFactory.java +++ b/Mage.Client/src/main/java/org/mage/card/arcane/CardRendererFactory.java @@ -1,6 +1,5 @@ package org.mage.card.arcane; -import mage.cards.ArtRect; import mage.view.CardView; /** @@ -12,9 +11,7 @@ public class CardRendererFactory { } public CardRenderer create(CardView card) { - if (card.isSplitCard() && card.getArtRect() != ArtRect.SPLIT_FUSED) { - // Split fused cards still render with the normal frame, showing all abilities - // from both halves in one frame. + if (card.isSplitCard()) { return new ModernSplitCardRenderer(card); } else { return new ModernCardRenderer(card); 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 48aa164387b..ba85e5f9002 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 @@ -15,14 +15,10 @@ import org.apache.log4j.Logger; import static org.mage.card.arcane.ManaSymbols.getSizedManaSymbol; import static org.mage.card.arcane.ModernCardResourceLoader.*; -import javax.swing.*; import java.awt.*; import java.awt.font.*; import java.awt.geom.*; import java.awt.image.BufferedImage; -import java.io.IOException; -import java.io.InputStream; -import java.net.URL; import java.text.AttributedCharacterIterator; import java.text.AttributedString; import java.text.CharacterIterator; @@ -147,6 +143,8 @@ public class ModernCardRenderer extends CardRenderer { public static final Color ERROR_COLOR = new Color(255, 0, 255); + static String SUB_TYPE_ADVENTURE = "Adventure"; + /////////////////////////////////////////////////////////////////////////// // Layout metrics for modern border cards // How far the main box, art, and name / type line are inset from the @@ -189,7 +187,10 @@ public class ModernCardRenderer extends CardRenderer { protected Font ptTextFont; // Processed mana cost string - protected final String manaCostString; + protected String manaCostString; + + // Is an adventure + protected boolean isAdventure = false; public ModernCardRenderer(CardView card) { // Pass off to parent @@ -197,6 +198,14 @@ public class ModernCardRenderer extends CardRenderer { // Mana cost string manaCostString = ManaSymbols.getClearManaCost(cardView.getManaCostStr()); + + if (cardView.isSplitCard()) { + isAdventure = cardView.getRightSplitTypeLine().contains(SUB_TYPE_ADVENTURE); + } + } + + protected boolean isAdventure() { + return isAdventure; } @Override @@ -406,19 +415,7 @@ public class ModernCardRenderer extends CardRenderer { if (cardView.getMageObjectType() == MageObjectType.SPELL) { useFaceArt = false; ArtRect rect = cardView.getArtRect(); - if (rect == ArtRect.SPLIT_FUSED) { - // Special handling for fused, draw the art from both halves stacked on top of one and other - // each filling half of the art rect - drawArtIntoRect(g, - totalContentInset + 1, totalContentInset + boxHeight, - contentWidth - 2, (typeLineY - totalContentInset - boxHeight) / 2, - ArtRect.SPLIT_LEFT.rect, useInventionFrame()); - drawArtIntoRect(g, - totalContentInset + 1, totalContentInset + boxHeight + (typeLineY - totalContentInset - boxHeight) / 2, - contentWidth - 2, (typeLineY - totalContentInset - boxHeight) / 2, - ArtRect.SPLIT_RIGHT.rect, useInventionFrame()); - return; - } else if (rect != ArtRect.NORMAL) { + if (rect != ArtRect.NORMAL) { sourceRect = rect.rect; shouldPreserveAspect = false; } @@ -701,6 +698,10 @@ public class ModernCardRenderer extends CardRenderer { drawRulesText(g, textboxKeywords, textboxRules, contentWidth / 2 + totalContentInset + 4, totalContentInset + boxHeight + 2, contentWidth / 2 - 8, typeLineY - totalContentInset - boxHeight - 6, false); + } else if (isAdventure) { + drawRulesText(g, textboxKeywords, textboxRules, + contentWidth / 2 + totalContentInset + 4, typeLineY + boxHeight + 2, + contentWidth / 2 - 8, cardHeight - typeLineY - boxHeight - 4 - borderWidth * 3, false); } else if (!isZenUst) { drawRulesText(g, textboxKeywords, textboxRules, totalContentInset + 2, typeLineY + boxHeight + 2, diff --git a/Mage.Client/src/main/java/org/mage/card/arcane/ModernSplitCardRenderer.java b/Mage.Client/src/main/java/org/mage/card/arcane/ModernSplitCardRenderer.java index 70aeef72643..011d4ab2796 100644 --- a/Mage.Client/src/main/java/org/mage/card/arcane/ModernSplitCardRenderer.java +++ b/Mage.Client/src/main/java/org/mage/card/arcane/ModernSplitCardRenderer.java @@ -18,6 +18,14 @@ import java.util.List; */ public class ModernSplitCardRenderer extends ModernCardRenderer { + public static final Color ADVENTURE_BOX_WHITE = new Color(135, 122, 103); + public static final Color ADVENTURE_BOX_BLUE = new Color(2, 96, 131); + public static final Color ADVENTURE_BOX_BLACK = new Color(52, 44, 46); + public static final Color ADVENTURE_BOX_RED = new Color(126, 61, 42); + public static final Color ADVENTURE_BOX_GREEN = new Color(9, 51, 30); + public static final Color ADVENTURE_BOX_GOLD = new Color(118, 92, 42); + public static final Color ADVENTURE_BOX_COLORLESS = new Color(131, 133, 135); + static String RULES_MARK_FUSE = "Fuse"; static String RULES_MARK_AFTERMATH = "Aftermath"; @@ -29,8 +37,8 @@ public class ModernSplitCardRenderer extends ModernCardRenderer { String typeLineString; String manaCostString; ObjectColor color; - List rules = new ArrayList<>(); - List keywords = new ArrayList<>(); + ArrayList rules = new ArrayList<>(); + ArrayList keywords = new ArrayList<>(); } private static final List ONLY_LAND_TYPE = Arrays.asList(CardType.LAND); @@ -47,6 +55,13 @@ public class ModernSplitCardRenderer extends ModernCardRenderer { private boolean isFuse = false; private boolean isAftermath = false; + private static String trimAdventure(String rule) { + if (rule.startsWith("Adventure")) { + return rule.substring(rule.lastIndexOf("—") + 8); + } + return rule; + } + public ModernSplitCardRenderer(CardView view) { super(view); @@ -56,7 +71,15 @@ public class ModernSplitCardRenderer extends ModernCardRenderer { rightHalf.color = new ObjectColor(cardView.getRightSplitCostsStr()); leftHalf.color = new ObjectColor(cardView.getLeftSplitCostsStr()); - parseRules(view.getRightSplitRules(), rightHalf.keywords, rightHalf.rules); + if (isAdventure()) { + List trimmedRules = new ArrayList<>(); + for (String rule : view.getRightSplitRules()) { + trimmedRules.add(trimAdventure(rule)); + } + parseRules(trimmedRules, rightHalf.keywords, rightHalf.rules); + } else { + parseRules(view.getRightSplitRules(), rightHalf.keywords, rightHalf.rules); + } parseRules(view.getLeftSplitRules(), leftHalf.keywords, leftHalf.rules); rightHalf.typeLineString = cardView.getRightSplitTypeLine(); @@ -71,7 +94,12 @@ public class ModernSplitCardRenderer extends ModernCardRenderer { // It's easier for rendering to swap the card halves here because for aftermath cards // they "rotate" in opposite directions making consquence and normal split cards // have the "right" vs "left" as the top half. - if (!isAftermath()) { + // Adventures are treated differently and not rotated at all. + if (isAdventure()) { + manaCostString = leftHalf.manaCostString; + textboxKeywords = leftHalf.keywords; + textboxRules = leftHalf.rules; + } else if (!isAftermath()) { HalfCardProps tmp = leftHalf; leftHalf = rightHalf; rightHalf = tmp; @@ -131,6 +159,8 @@ public class ModernSplitCardRenderer extends ModernCardRenderer { protected void drawBackground(Graphics2D g) { if (cardView.isFaceDown()) { drawCardBack(g); + } if (isAdventure()) { + super.drawBackground(g); } else { { // Left half background (top of the card) // Set texture to paint the left with @@ -174,7 +204,9 @@ public class ModernSplitCardRenderer extends ModernCardRenderer { @Override protected void drawArt(Graphics2D g) { - if (artImage != null && !cardView.isFaceDown()) { + if (isAdventure) { + super.drawArt(g); + } else if (artImage != null && !cardView.isFaceDown()) { if (isAftermath()) { Rectangle2D topRect = ArtRect.AFTERMATH_TOP.rect; int topLineY = (int) (leftHalf.ch * TYPE_LINE_Y_FRAC); @@ -286,7 +318,43 @@ public class ModernSplitCardRenderer extends ModernCardRenderer { @Override protected void drawFrame(Graphics2D g, CardPanelAttributes attribs, BufferedImage image, boolean lessOpaqueRulesTextBox) { - if (isAftermath()) { + if (isAdventure()) { + super.drawFrame(g, attribs, image, lessOpaqueRulesTextBox); + + CardPanelAttributes adventureAttribs = new CardPanelAttributes( + attribs.cardWidth, attribs.cardHeight, attribs.isChoosable, + attribs.isSelected, true); + + // Draw the adventure name line box + g.setPaint(getBoxColor(rightHalf.color, cardView.getCardTypes(), true)); + g.fillRect(totalContentInset, typeLineY + boxHeight + 1, + contentWidth / 2 - 1, boxHeight - 2); + + // Draw the adventure type line box + g.setPaint(getAdventureBoxColor(rightHalf.color)); + g.fillRect(totalContentInset , typeLineY + boxHeight * 2 - 1, + contentWidth / 2 - 1, boxHeight - 2); + + // Draw the adventure text box + g.setPaint(getTextboxPaint(rightHalf.color, cardView.getCardTypes(), cardWidth, lessOpaqueRulesTextBox)); + g.fillRect(totalContentInset, typeLineY + boxHeight * 3 - 3, + contentWidth / 2 - 1, cardHeight - borderWidth * 3 - typeLineY - boxHeight * 3 + 2); + + // Draw the adventure name line + drawNameLine(g, adventureAttribs, rightHalf.name, rightHalf.manaCostString, + totalContentInset + 2, typeLineY + boxHeight, + contentWidth / 2 - 8, boxHeight - 2); + + // Draw the adventure type line + drawTypeLine(g, adventureAttribs, rightHalf.typeLineString, + totalContentInset + 2, typeLineY + boxHeight * 2 - 2, + contentWidth / 2 - 8, boxHeight - 2, true); + + // Draw the adventure textbox rules + drawRulesText(g, rightHalf.keywords, rightHalf.rules, + totalContentInset + 3, typeLineY + boxHeight * 3 - 1, + contentWidth / 2 - 8, cardHeight - borderWidth * 3 - typeLineY - boxHeight * 3 + 2, false); + } else if (isAftermath()) { drawSplitHalfFrame(getUnmodifiedHalfContext(g), attribs, leftHalf, (int) (leftHalf.ch * TYPE_LINE_Y_FRAC)); drawSplitHalfFrame(getAftermathHalfContext(g), attribs, rightHalf, (rightHalf.ch - boxHeight) / 2); } else { @@ -308,4 +376,24 @@ public class ModernSplitCardRenderer extends ModernCardRenderer { } } } + + protected Color getAdventureBoxColor(ObjectColor colors) { + if (colors.isMulticolored()) { + return ADVENTURE_BOX_GOLD; + } else if (colors.isColorless()) { + return ADVENTURE_BOX_COLORLESS; + } else if (colors.isWhite()) { + return ADVENTURE_BOX_WHITE; + } else if (colors.isBlue()) { + return ADVENTURE_BOX_BLUE; + } else if (colors.isBlack()) { + return ADVENTURE_BOX_BLACK; + } else if (colors.isRed()) { + return ADVENTURE_BOX_RED; + } else if (colors.isGreen()) { + return ADVENTURE_BOX_GREEN; + } else { + return ERROR_COLOR; + } + } } diff --git a/Mage.Common/src/main/java/mage/view/CardView.java b/Mage.Common/src/main/java/mage/view/CardView.java index 96c296e236c..340e9653ba2 100644 --- a/Mage.Common/src/main/java/mage/view/CardView.java +++ b/Mage.Common/src/main/java/mage/view/CardView.java @@ -398,11 +398,20 @@ public class CardView extends SimpleCardView { this.manaCostLeftStr = mainCard.getLeftHalfCard().getManaCostSymbols(); this.manaCostRightStr = mainCard.getRightHalfCard().getManaCostSymbols(); } else if (card instanceof AdventureCard) { + this.isSplitCard = true; AdventureCard adventureCard = ((AdventureCard) card); + leftSplitName = adventureCard.getName(); + leftSplitCostsStr = String.join("", adventureCard.getManaCostSymbols()); + leftSplitRules = adventureCard.getSharedRules(game); + leftSplitTypeLine = getCardTypeLine(game, adventureCard); AdventureCardSpell adventureCardSpell = adventureCard.getSpellCard(); + rightSplitName = adventureCardSpell.getName(); + rightSplitCostsStr = String.join("", adventureCardSpell.getManaCostSymbols()); + rightSplitRules = adventureCardSpell.getRules(game); + rightSplitTypeLine = getCardTypeLine(game, adventureCardSpell); fullCardName = adventureCard.getName() + MockCard.ADVENTURE_NAME_SEPARATOR + adventureCardSpell.getName(); - this.manaCostLeftStr = adventureCardSpell.getManaCostSymbols(); - this.manaCostRightStr = adventureCard.getManaCostSymbols(); + this.manaCostLeftStr = adventureCard.getManaCostSymbols(); + this.manaCostRightStr = adventureCardSpell.getManaCostSymbols(); } else if (card instanceof MockCard) { // deck editor cards fullCardName = ((MockCard) card).getFullName(true); diff --git a/Mage/src/main/java/mage/cards/AdventureCard.java b/Mage/src/main/java/mage/cards/AdventureCard.java index 875e1095233..080ab85c040 100644 --- a/Mage/src/main/java/mage/cards/AdventureCard.java +++ b/Mage/src/main/java/mage/cards/AdventureCard.java @@ -9,6 +9,7 @@ import mage.constants.SpellAbilityType; import mage.constants.Zone; import mage.game.Game; import mage.game.events.ZoneChangeEvent; +import mage.util.CardUtil; import java.util.List; import java.util.UUID; @@ -129,6 +130,12 @@ public abstract class AdventureCard extends CardImpl { return super.getAbilities(game); } + public List getSharedRules(Game game) { + // rules without spellcard + Abilities sourceAbilities = this.getSharedAbilities(game); + return CardUtil.getCardRulesWithAdditionalInfo(game, this.getId(), this.getName(), sourceAbilities, sourceAbilities); + } + @Override public void setOwnerId(UUID ownerId) { super.setOwnerId(ownerId); diff --git a/Mage/src/main/java/mage/cards/AdventureCardSpellImpl.java b/Mage/src/main/java/mage/cards/AdventureCardSpellImpl.java index 414fe262aa7..2062b27ca9e 100644 --- a/Mage/src/main/java/mage/cards/AdventureCardSpellImpl.java +++ b/Mage/src/main/java/mage/cards/AdventureCardSpellImpl.java @@ -181,4 +181,4 @@ class AdventureCardSpellAbility extends SpellAbility { public AdventureCardSpellAbility copy() { return new AdventureCardSpellAbility(this); } -} \ No newline at end of file +}