From 5062c8409866afe39d4559acef99723f72890364 Mon Sep 17 00:00:00 2001 From: Susucre <34709007+Susucre@users.noreply.github.com> Date: Thu, 24 Aug 2023 10:04:07 +0200 Subject: [PATCH] Refactor: removed server side objects from a client side game's data (#10788) * Clean original values transmitted with CardView.originalObject * Move RateCard to mage.Common, support cardView as argument. * Clean PermanentView constructor for TestCardRenderDialog --- .../src/main/java/mage/client/MageFrame.java | 3 +- .../collection/viewer/MageBook.java | 9 +- .../deckeditor/table/MageCardComparator.java | 6 +- .../client/deckeditor/table/TableModel.java | 4 +- .../client/dialog/TestCardRenderDialog.java | 7 +- .../card/arcane/CardPanelRenderModeImage.java | 16 +- .../mage/card/arcane/ModernCardRenderer.java | 16 +- .../src/main/java/mage/cards}/RateCard.java | 169 +++++++++++++----- .../src/main/java/mage/view/AbilityView.java | 4 +- .../src/main/java/mage/view/CardView.java | 136 +++++++++----- .../main/java/mage/view/PermanentView.java | 37 +++- .../main/java/mage/view/StackAbilityView.java | 12 +- Mage.Server.Plugins/Mage.Player.AI/pom.xml | 5 + .../java/mage/player/ai/ComputerPlayer.java | 2 +- .../src/main/java/mage/server/Main.java | 2 +- .../mage/test/serverside/CardIconsTest.java | 4 +- .../java/mage/verify/VerifyCardDataTest.java | 2 +- 17 files changed, 285 insertions(+), 149 deletions(-) rename {Mage/src/main/java/mage/game/draft => Mage.Common/src/main/java/mage/cards}/RateCard.java (75%) diff --git a/Mage.Client/src/main/java/mage/client/MageFrame.java b/Mage.Client/src/main/java/mage/client/MageFrame.java index 2cff98961e0..c2483cfe6e4 100644 --- a/Mage.Client/src/main/java/mage/client/MageFrame.java +++ b/Mage.Client/src/main/java/mage/client/MageFrame.java @@ -37,7 +37,7 @@ import mage.client.util.stats.UpdateMemUsageTask; import mage.components.ImagePanel; import mage.components.ImagePanelStyle; import mage.constants.PlayerAction; -import mage.game.draft.RateCard; +import mage.cards.RateCard; import mage.interfaces.MageClient; import mage.interfaces.callback.CallbackClient; import mage.interfaces.callback.ClientCallback; @@ -73,7 +73,6 @@ import java.io.InputStream; import java.net.SocketException; import java.net.URI; import java.net.URISyntaxException; -import java.net.URL; import java.nio.charset.Charset; import java.util.*; import java.util.concurrent.Executors; diff --git a/Mage.Client/src/main/java/mage/client/deckeditor/collection/viewer/MageBook.java b/Mage.Client/src/main/java/mage/client/deckeditor/collection/viewer/MageBook.java index 0d32168e14a..830f0506cc0 100644 --- a/Mage.Client/src/main/java/mage/client/deckeditor/collection/viewer/MageBook.java +++ b/Mage.Client/src/main/java/mage/client/deckeditor/collection/viewer/MageBook.java @@ -1,5 +1,6 @@ package mage.client.deckeditor.collection.viewer; +import static java.lang.Math.min; import mage.abilities.icon.CardIconRenderSettings; import mage.cards.CardDimensions; import mage.cards.ExpansionSet; @@ -21,7 +22,7 @@ import mage.components.ImagePanelStyle; import mage.game.command.Dungeon; import mage.game.command.Emblem; import mage.game.command.Plane; -import mage.game.draft.RateCard; +import mage.cards.RateCard; import mage.game.permanent.PermanentToken; import mage.game.permanent.token.Token; import mage.game.permanent.token.TokenImpl; @@ -42,8 +43,6 @@ import java.util.UUID; import java.util.stream.Collectors; import java.util.stream.IntStream; -import static java.lang.Math.min; - /** * Card viewer (mage book) with cards and page flipping * @@ -388,9 +387,9 @@ public class MageBook extends JComponent { draftRating.setBounds(rectangle.x, rectangle.y + cardImg.getCardLocation().getCardHeight() + dy, cardDimensions.getFrameWidth(), 20); draftRating.setHorizontalAlignment(SwingConstants.CENTER); draftRating.setFont(jLayeredPane.getFont().deriveFont(jLayeredPane.getFont().getStyle() | Font.BOLD)); - if (card.getOriginalCard() != null) { + if (card.isOriginalACard()) { // card - draftRating.setText("draft rating: " + RateCard.rateCard(card.getOriginalCard(), null)); + draftRating.setText("draft rating: " + RateCard.rateCard(card, null)); } else { // token draftRating.setText(""); diff --git a/Mage.Client/src/main/java/mage/client/deckeditor/table/MageCardComparator.java b/Mage.Client/src/main/java/mage/client/deckeditor/table/MageCardComparator.java index d14d236c145..51542210539 100644 --- a/Mage.Client/src/main/java/mage/client/deckeditor/table/MageCardComparator.java +++ b/Mage.Client/src/main/java/mage/client/deckeditor/table/MageCardComparator.java @@ -2,7 +2,7 @@ package mage.client.deckeditor.table; import mage.cards.MageCard; import mage.client.util.comparators.CardViewComparator; -import mage.game.draft.RateCard; +import mage.cards.RateCard; import mage.view.CardView; import org.apache.log4j.Logger; @@ -83,8 +83,8 @@ public class MageCardComparator implements CardViewComparator { bCom = Integer.parseInt(b.getCardNumber().replaceAll("[\\D]", "")); break; case 9: - aCom = RateCard.rateCard(a.getOriginalCard(), null); - bCom = RateCard.rateCard(b.getOriginalCard(), null); + aCom = RateCard.rateCard(a, null); + bCom = RateCard.rateCard(b, null); break; case 10: aCom = a.getColorIdentityStr(); diff --git a/Mage.Client/src/main/java/mage/client/deckeditor/table/TableModel.java b/Mage.Client/src/main/java/mage/client/deckeditor/table/TableModel.java index 772945b281f..1bdeafa67ad 100644 --- a/Mage.Client/src/main/java/mage/client/deckeditor/table/TableModel.java +++ b/Mage.Client/src/main/java/mage/client/deckeditor/table/TableModel.java @@ -12,7 +12,7 @@ import mage.client.util.Event; import mage.client.util.Listener; import mage.client.util.gui.GuiDisplayUtil; import mage.constants.EnlargeMode; -import mage.game.draft.RateCard; +import mage.cards.RateCard; import mage.view.CardView; import mage.view.CardsView; import org.apache.log4j.Logger; @@ -253,7 +253,7 @@ public class TableModel extends AbstractTableModel implements ICardGrid { case 8: return c.getCardNumber(); case 9: - return RateCard.rateCard(c.getOriginalCard(), null); + return RateCard.rateCard(c, null); case 10: return ManaSymbols.getClearManaCost(c.getColorIdentityStr()); default: 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 490a0fa3daa..59d300743f9 100644 --- a/Mage.Client/src/main/java/mage/client/dialog/TestCardRenderDialog.java +++ b/Mage.Client/src/main/java/mage/client/dialog/TestCardRenderDialog.java @@ -28,7 +28,6 @@ import mage.game.command.Plane; import mage.game.match.MatchType; import mage.game.mulligan.Mulligan; import mage.game.mulligan.MulliganType; -import mage.game.permanent.Permanent; import mage.game.permanent.PermanentCard; import mage.game.permanent.PermanentMeld; import mage.game.permanent.PermanentToken; @@ -402,9 +401,9 @@ public class TestCardRenderDialog extends MageDialog { if (main.getGameCard() instanceof PermanentView) { // new settings must be as a new copy -- it would activate the animations PermanentView oldPermanent = (PermanentView) main.getGameCard(); - PermanentView newPermament = new PermanentView( // ??? - (Permanent) oldPermanent.getOriginalCard(), - game.getCard(oldPermanent.getOriginalCard().getId()), + PermanentView newPermament = new PermanentView( + oldPermanent, + game.getCard(oldPermanent.getOriginalId()), UUID.randomUUID(), game ); diff --git a/Mage.Client/src/main/java/org/mage/card/arcane/CardPanelRenderModeImage.java b/Mage.Client/src/main/java/org/mage/card/arcane/CardPanelRenderModeImage.java index 4af6af1f7f6..fc3c365a3d5 100644 --- a/Mage.Client/src/main/java/org/mage/card/arcane/CardPanelRenderModeImage.java +++ b/Mage.Client/src/main/java/org/mage/card/arcane/CardPanelRenderModeImage.java @@ -446,20 +446,8 @@ public class CardPanelRenderModeImage extends CardPanel { if (cardView.showPT()) { // real PT info - MageInt currentPower; - MageInt currentToughness; - if (cardView.getOriginalCard() != null) { - // card - currentPower = cardView.getOriginalCard().getPower(); - currentToughness = cardView.getOriginalCard().getToughness(); - } else if (cardView.getOriginalToken() != null) { - // token - currentPower = cardView.getOriginalToken().getPower(); - currentToughness = cardView.getOriginalToken().getToughness(); - } else { - currentPower = null; - currentToughness = null; - } + MageInt currentPower = cardView.getOriginalPower(); + MageInt currentToughness = cardView.getOriginalToughness(); prepareGlowFont(ptText1, Math.max(CARD_PT_FONT_MIN_SIZE, fontSize), currentPower, false); prepareGlowFont(ptText2, Math.max(CARD_PT_FONT_MIN_SIZE, fontSize), null, false); 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 38fd5a856c4..8b3ec481969 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 @@ -1096,20 +1096,8 @@ public class ModernCardRenderer extends CardRenderer { g.setFont(ptTextFont); // real PT info - MageInt currentPower; - MageInt currentToughness; - if (cardView.getOriginalCard() != null) { - // card - currentPower = cardView.getOriginalCard().getPower(); - currentToughness = cardView.getOriginalCard().getToughness(); - } else if (cardView.getOriginalToken() != null) { - // token - currentPower = cardView.getOriginalToken().getPower(); - currentToughness = cardView.getOriginalToken().getToughness(); - } else { - currentPower = null; - currentToughness = null; - } + MageInt currentPower = cardView.getOriginalPower(); + MageInt currentToughness = cardView.getOriginalToughness(); // draws int ptEmptySpace = (partBoxWidth - ptContentWidth) / 2; diff --git a/Mage/src/main/java/mage/game/draft/RateCard.java b/Mage.Common/src/main/java/mage/cards/RateCard.java similarity index 75% rename from Mage/src/main/java/mage/game/draft/RateCard.java rename to Mage.Common/src/main/java/mage/cards/RateCard.java index 0966c7852f5..58c01c5c8c2 100644 --- a/Mage/src/main/java/mage/game/draft/RateCard.java +++ b/Mage.Common/src/main/java/mage/cards/RateCard.java @@ -1,19 +1,18 @@ -package mage.game.draft; +package mage.cards; import mage.abilities.Ability; import mage.abilities.Mode; import mage.abilities.effects.Effect; import mage.abilities.effects.common.*; -import mage.abilities.effects.common.continuous.BoostEnchantedEffect; -import mage.abilities.effects.common.continuous.BoostTargetEffect; -import mage.cards.Card; import mage.cards.repository.CardScanner; import mage.constants.ColoredManaSymbol; import mage.constants.Outcome; +import mage.constants.Rarity; import mage.constants.SubType; import mage.target.Target; import mage.target.TargetPermanent; import mage.target.common.TargetPlayerOrPlaneswalker; +import mage.view.CardView; import org.apache.log4j.Logger; import java.io.InputStream; @@ -30,7 +29,8 @@ public final class RateCard { public static final boolean PRELOAD_CARD_RATINGS_ON_STARTUP = false; // warning, rating and card classes preloading can cause lags for users with low memory private static Map baseRatings = new HashMap<>(); - private static final Map rated = new HashMap<>(); + private static final Map ratedCard = new HashMap<>(); + private static final Map ratedCardView = new HashMap<>(); // Rating is not exactly the same for CardView, so cached in a different map. private static boolean isLoaded = false; /** @@ -80,42 +80,96 @@ public final class RateCard { return rateCard(card, allowedColors, true); } + public static int rateCard(CardView cardview, List allowedColors) { + return rateCard(cardview, allowedColors, true); + } + public static int rateCard(Card card, List allowedColors, boolean useCache) { if (card == null) { return 0; } - if (useCache && allowedColors == null && rated.containsKey(card.getName())) { - int rate = rated.get(card.getName()); + String name = card.getName(); + if (useCache && allowedColors == null && ratedCard.containsKey(name)) { + int rate = ratedCard.get(name); return rate; } - int type; - if (card.isPlaneswalker()) { - type = 15; - } else if (card.isCreature()) { - type = 10; - } else if (card.getSubtype().contains(SubType.EQUIPMENT)) { - type = 8; - } else if (card.getSubtype().contains(SubType.AURA)) { - type = 5; - } else if (card.isInstant()) { - type = 7; - } else { - type = 6; - } - int score = getBaseCardScore(card) + 2 * type + getManaCostScore(card, allowedColors) + int typeMultiplier = typeMultiplier(card); + int score = getBaseCardScore(card) + 2 * typeMultiplier + getManaCostScore(card, allowedColors) + 40 * isRemoval(card); if (useCache && allowedColors == null) - rated.put(card.getName(), score); + ratedCard.put(name, score); return score; } + public static int rateCard(CardView cardview, List allowedColors, boolean useCache) { + if (cardview == null) { + return 0; + } + + String name = cardview.getName(); + if (useCache && allowedColors == null && ratedCardView.containsKey(name)) { + int rate = ratedCardView.get(name); + return rate; + } + + int typeMultiplier = typeMultiplier(cardview); + int score = getBaseCardScore(cardview) + 2 * typeMultiplier + getManaCostScore(cardview, allowedColors); + // Cardview does not have enough info to know the card is a removal. + + if (useCache && allowedColors == null) + ratedCardView.put(name, score); + + return score; + } + + protected static int typeMultiplier(Card card) { + return typeMultiplier( + card.isPlaneswalker(), + card.isCreature(), + card.getSubtype().contains(SubType.EQUIPMENT), + card.getSubtype().contains(SubType.AURA), + card.isInstant() + ); + } + + protected static int typeMultiplier(CardView cardview) { + return typeMultiplier( + cardview.isPlaneswalker(), + cardview.isCreature(), + cardview.getSubTypes().contains(SubType.EQUIPMENT), + cardview.getSubTypes().contains(SubType.AURA), + cardview.isInstant() + ); + } + + protected static int typeMultiplier( + boolean isPlaneswalker, + boolean isCreature, + boolean isEquipment, + boolean isAura, + boolean isInstant + ) { + if (isPlaneswalker) { + return 15; + } else if (isCreature) { + return 10; + } else if (isEquipment) { + return 8; + } else if (isAura) { + return 5; + } else if (isInstant) { + return 7; + } else { + return 6; + } + } + private static int isRemoval(Card card) { if (card.isEnchantment() || card.isInstantOrSorcery()) { - for (Ability ability : card.getAbilities()) { for (Effect effect : ability.getEffects()) { if (isEffectRemoval(card, ability, effect) == 1) { @@ -130,7 +184,6 @@ public final class RateCard { } } } - } return 0; } @@ -168,7 +221,6 @@ public final class RateCard { return 0; } - /** * Return rating of the card. * @@ -176,6 +228,20 @@ public final class RateCard { * @return Rating number from [1:100]. */ public static int getBaseCardScore(Card card) { + return getBaseScore( + card.getName(), + card.getRarity() + ); + } + + public static int getBaseCardScore(CardView cardview) { + return getBaseScore( + cardview.getName(), + cardview.getRarity() + ); + } + + protected static int getBaseScore(String name, Rarity rarity) { // same card name must have same rating // ratings from files @@ -185,8 +251,8 @@ public final class RateCard { // ratings from card rarity // some cards can have different rarity -- it's will be used from first set int newRating; - if (card.getRarity() != null) { - switch (card.getRarity()) { + if (rarity != null) { + switch (rarity) { case COMMON: newRating = DEFAULT_NOT_RATED_CARD_RATING; break; @@ -200,7 +266,7 @@ public final class RateCard { newRating = DEFAULT_NOT_RATED_MYTHIC_RATING; break; default: - if (isBasicLand(card)) { + if (isBasicLand(name)) { newRating = DEFAULT_BASIC_LAND_RATING; } else { newRating = DEFAULT_NOT_RATED_CARD_RATING; @@ -212,7 +278,7 @@ public final class RateCard { newRating = DEFAULT_NOT_RATED_CARD_RATING; } - int oldRating = baseRatings.getOrDefault(card.getName(), 0); + int oldRating = baseRatings.getOrDefault(name, 0); if (oldRating != 0 && oldRating != newRating) { //log.info("card have different rating by sets: " + card.getName() + " (" + oldRating + " <> " + newRating + ")"); } @@ -220,7 +286,7 @@ public final class RateCard { if (oldRating != 0) { return oldRating; } else { - baseRatings.put(card.getName(), newRating); + baseRatings.put(name, newRating); return newRating; } } @@ -316,26 +382,44 @@ public final class RateCard { * @param allowedColors Can be null. * @return */ + private static int getManaCostScore(Card card, List allowedColors) { - int converted = card.getManaValue(); + return getManaCostScore( + card.getName(), + card.getManaValue(), + card.getManaCostSymbols(), + allowedColors + ); + } + + private static int getManaCostScore(CardView cardview, List allowedColors) { + return getManaCostScore( + cardview.getName(), + cardview.getManaValue(), + cardview.getManaCostSymbols(), + allowedColors + ); + } + + private static int getManaCostScore(String name, int manaValue, List manaCostSymbols, List allowedColors) { if (allowedColors == null) { int colorPenalty = 0; - for (String symbol : card.getManaCostSymbols()) { + for (String symbol : manaCostSymbols) { if (isColoredMana(symbol)) { colorPenalty++; } } - return 2 * (converted - colorPenalty + 1); + return 2 * (manaValue - colorPenalty + 1); } - + // Basic lands have no value so they're always treated as off-color - if (isBasicLand(card)) { + if (isBasicLand(name)) { return OFF_COLOR_PENALTY; } - + final Map singleCount = new HashMap<>(); int maxSingleCount = 0; - for (String symbol : card.getManaCostSymbols()) { + for (String symbol : manaCostSymbols) { int count = 0; symbol = symbol.replace("{", "").replace("}", ""); if (isColoredMana(symbol)) { @@ -359,7 +443,7 @@ public final class RateCard { if (maxSingleCount > 5) maxSingleCount = 5; - int rate = 2 * converted + 3 * (10 - SINGLE_PENALTY[maxSingleCount]); + int rate = 2 * manaValue + 3 * (10 - SINGLE_PENALTY[maxSingleCount]); if (singleCount.size() > 1 && singleCount.size() < 5) { rate += MULTICOLOR_BONUS; } @@ -414,15 +498,14 @@ public final class RateCard { } return symbols.size(); } - + /** * Return true if the card is one of the basic land types that can be added to the deck for free. * - * @param card + * @param name * @return */ - public static boolean isBasicLand(Card card) { - String name = card.getName(); + public static boolean isBasicLand(String name) { if (name.equals("Plains") || name.equals("Island") || name.equals("Swamp") diff --git a/Mage.Common/src/main/java/mage/view/AbilityView.java b/Mage.Common/src/main/java/mage/view/AbilityView.java index 1a0a7540518..5a49c0296c0 100644 --- a/Mage.Common/src/main/java/mage/view/AbilityView.java +++ b/Mage.Common/src/main/java/mage/view/AbilityView.java @@ -31,8 +31,8 @@ public class AbilityView extends CardView { this.subTypes = new SubTypes(); this.superTypes = new ArrayList<>(); this.color = new ObjectColor(); - this.manaCostLeftStr = String.join("", ability.getManaCostSymbols()); - this.manaCostRightStr = ""; + this.manaCostLeftStr = ability.getManaCostSymbols(); + this.manaCostRightStr = new ArrayList<>(); } public CardView getSourceCard() { diff --git a/Mage.Common/src/main/java/mage/view/CardView.java b/Mage.Common/src/main/java/mage/view/CardView.java index 13ade6765a1..0112f3f13fd 100644 --- a/Mage.Common/src/main/java/mage/view/CardView.java +++ b/Mage.Common/src/main/java/mage/view/CardView.java @@ -1,6 +1,7 @@ package mage.view; import com.google.gson.annotations.Expose; +import mage.MageInt; import mage.MageObject; import mage.ObjectColor; import mage.abilities.Abilities; @@ -74,8 +75,8 @@ public class CardView extends SimpleCardView { protected ObjectColor frameColor; protected FrameStyle frameStyle; // can combine multiple costs for MockCard from deck editor or db (left/right, card/adventure) - protected String manaCostLeftStr; - protected String manaCostRightStr; + protected List manaCostLeftStr; + protected List manaCostRightStr; protected int manaValue; protected Rarity rarity; @@ -130,7 +131,13 @@ public class CardView extends SimpleCardView { protected boolean inViewerOnly; // GUI render: show object as a card instead permanent (without PT, etc) protected List cardIcons = new ArrayList<>(); // additional icons to render - protected MageObject originalObject = null; // GUI related: additional info about current object (example: real PT) + // GUI related: additional info about current object (example: real PT) + protected MageInt originalPower = null; + protected MageInt originalToughness = null; + protected FilterMana originalColorIdentity = null; + protected UUID originalId = null; + protected boolean originalIsCopy = false; + protected boolean originalIsCard = false; /** * Non game usage like deck editor @@ -237,7 +244,12 @@ public class CardView extends SimpleCardView { this.canAttack = cardView.canAttack; this.canBlock = cardView.canBlock; this.inViewerOnly = cardView.inViewerOnly; - this.originalObject = cardView.originalObject == null ? null : cardView.originalObject.copy(); + this.originalPower = cardView.originalPower; + this.originalToughness = cardView.originalToughness; + this.originalColorIdentity = cardView.originalColorIdentity; + this.originalId = cardView.originalId; + this.originalIsCard = cardView.originalIsCard; + this.originalIsCopy = cardView.originalIsCopy; if (cardView.cardIcons != null) { cardView.cardIcons.forEach(icon -> this.cardIcons.add(icon.copy())); } @@ -287,7 +299,7 @@ public class CardView extends SimpleCardView { */ public CardView(Card card, Game game, boolean controlled, boolean showFaceDownCard, boolean storeZone) { super(card.getId(), card.getExpansionSetCode(), card.getCardNumber(), card.getUsesVariousArt(), game != null); - this.originalObject = card; + this.setOriginalValues(card); this.imageNumber = card.getImageNumber(); // no information available for face down cards as long it's not a controlled face down morph card @@ -375,29 +387,29 @@ public class CardView extends SimpleCardView { rightSplitTypeLine = getCardTypeLine(game, splitCard.getRightHalfCard()); fullCardName = card.getName(); // split card contains full name as normal - this.manaCostLeftStr = String.join("", splitCard.getLeftHalfCard().getManaCostSymbols()); - this.manaCostRightStr = String.join("", splitCard.getRightHalfCard().getManaCostSymbols()); + this.manaCostLeftStr = splitCard.getLeftHalfCard().getManaCostSymbols(); + this.manaCostRightStr = splitCard.getRightHalfCard().getManaCostSymbols(); } else if (card instanceof ModalDoubleFacedCard) { this.isModalDoubleFacedCard = true; ModalDoubleFacedCard mainCard = ((ModalDoubleFacedCard) card); fullCardName = mainCard.getLeftHalfCard().getName() + MockCard.MODAL_DOUBLE_FACES_NAME_SEPARATOR + mainCard.getRightHalfCard().getName(); - this.manaCostLeftStr = String.join("", mainCard.getLeftHalfCard().getManaCostSymbols()); - this.manaCostRightStr = String.join("", mainCard.getRightHalfCard().getManaCostSymbols()); + this.manaCostLeftStr = mainCard.getLeftHalfCard().getManaCostSymbols(); + this.manaCostRightStr = mainCard.getRightHalfCard().getManaCostSymbols(); } else if (card instanceof AdventureCard) { AdventureCard adventureCard = ((AdventureCard) card); AdventureCardSpell adventureCardSpell = adventureCard.getSpellCard(); fullCardName = adventureCard.getName() + MockCard.ADVENTURE_NAME_SEPARATOR + adventureCardSpell.getName(); - this.manaCostLeftStr = String.join("", adventureCardSpell.getManaCostSymbols()); - this.manaCostRightStr = String.join("", adventureCard.getManaCostSymbols()); + this.manaCostLeftStr = adventureCardSpell.getManaCostSymbols(); + this.manaCostRightStr = adventureCard.getManaCostSymbols(); } else if (card instanceof MockCard) { // deck editor cards fullCardName = ((MockCard) card).getFullName(true); - this.manaCostLeftStr = String.join("", ((MockCard) card).getManaCostStr(CardInfo.ManaCostSide.LEFT)); - this.manaCostRightStr = String.join("", ((MockCard) card).getManaCostStr(CardInfo.ManaCostSide.RIGHT)); + this.manaCostLeftStr = ((MockCard) card).getManaCostStr(CardInfo.ManaCostSide.LEFT); + this.manaCostRightStr = ((MockCard) card).getManaCostStr(CardInfo.ManaCostSide.RIGHT); } else { fullCardName = card.getName(); - this.manaCostLeftStr = String.join("", card.getManaCostSymbols()); - this.manaCostRightStr = ""; + this.manaCostLeftStr = card.getManaCostSymbols(); + this.manaCostRightStr = new ArrayList<>(); } this.name = card.getName(); @@ -616,7 +628,7 @@ public class CardView extends SimpleCardView { public CardView(MageObject object, Game game) { super(object.getId(), object.getExpansionSetCode(), object.getCardNumber(), false, true); - this.originalObject = object; + this.setOriginalValues(object); this.imageNumber = object.getImageNumber(); this.name = object.getName(); @@ -638,8 +650,8 @@ public class CardView extends SimpleCardView { this.subTypes = object.getSubtype(game).copy(); this.superTypes = new ArrayList<>(object.getSuperType(game)); this.color = object.getColor(game).copy(); - this.manaCostLeftStr = String.join("", object.getManaCostSymbols()); - this.manaCostRightStr = ""; + this.manaCostLeftStr = object.getManaCostSymbols(); + this.manaCostRightStr = new ArrayList<>(); this.manaValue = object.getManaCost().manaValue(); if (object instanceof PermanentToken) { this.mageObjectType = MageObjectType.TOKEN; @@ -694,7 +706,6 @@ public class CardView extends SimpleCardView { public CardView(EmblemView emblem) { this(true); - this.originalObject = null; this.gameObject = true; this.id = emblem.getId(); this.mageObjectType = MageObjectType.EMBLEM; @@ -716,7 +727,6 @@ public class CardView extends SimpleCardView { public CardView(DungeonView dungeon) { this(true); - this.originalObject = null; this.gameObject = true; this.id = dungeon.getId(); this.mageObjectType = MageObjectType.DUNGEON; @@ -738,7 +748,6 @@ public class CardView extends SimpleCardView { public CardView(PlaneView plane) { this(true); - this.originalObject = null; this.gameObject = true; this.id = plane.getId(); this.mageObjectType = MageObjectType.PLANE; @@ -761,7 +770,6 @@ public class CardView extends SimpleCardView { public CardView(Designation designation, StackAbility stackAbility) { this(true); - this.originalObject = null; this.gameObject = true; this.id = designation.getId(); this.mageObjectType = MageObjectType.NULL; @@ -788,7 +796,6 @@ public class CardView extends SimpleCardView { } private void fillEmpty(Card card, boolean controlled) { - this.originalObject = null; this.name = "Face Down"; this.displayName = name; this.displayFullName = name; @@ -805,8 +812,8 @@ public class CardView extends SimpleCardView { this.color = new ObjectColor(); this.frameColor = new ObjectColor(); this.frameStyle = FrameStyle.M15_NORMAL; - this.manaCostLeftStr = ""; - this.manaCostRightStr = ""; + this.manaCostLeftStr = new ArrayList<>(); + this.manaCostRightStr = new ArrayList<>(); this.manaValue = 0; // the controller can see more information (e.g. enlarged image) than other players for face down cards (e.g. Morph played face down) @@ -857,8 +864,8 @@ public class CardView extends SimpleCardView { this.color = token.getColor(game).copy(); this.frameColor = token.getFrameColor(game).copy(); this.frameStyle = token.getFrameStyle(); - this.manaCostLeftStr = String.join("", token.getManaCostSymbols()); - this.manaCostRightStr = ""; + this.manaCostLeftStr = token.getManaCostSymbols(); + this.manaCostRightStr = new ArrayList<>(); this.rarity = Rarity.SPECIAL; // source object is a token, so no card number @@ -894,6 +901,26 @@ public class CardView extends SimpleCardView { this.targets.addAll(newTargets); } + private void setOriginalValues(MageObject object) { + if (object == null) { + return; + } + // Only valid objects to transfer original values are Card and Token + if (object instanceof Card || object instanceof Token) { + this.originalPower = object.getPower(); + this.originalToughness = object.getToughness(); + this.originalIsCopy = object.isCopy(); + this.originalId = object.getId(); + + if (object instanceof Card) { + this.originalColorIdentity = ((Card) object).getColorIdentity(); + this.originalIsCard = true; + } else if (object instanceof Token) { + this.originalColorIdentity = ManaUtil.getColorIdentity((Token) object); + } + } + } + public String getName() { return name; } @@ -979,7 +1006,22 @@ public class CardView extends SimpleCardView { } public String getManaCostStr() { - return CardUtil.concatManaSymbols(CardInfo.SPLIT_MANA_SEPARATOR_FULL, this.manaCostLeftStr, this.manaCostRightStr); + return CardUtil.concatManaSymbols( + CardInfo.SPLIT_MANA_SEPARATOR_FULL, + String.join("", this.manaCostLeftStr), + String.join("", this.manaCostRightStr) + ); + } + + public List getManaCostSymbols() { + List symbols = new ArrayList<>(); + for (String symbol : this.manaCostLeftStr) { + symbols.add(symbol); + } + for (String symbol : this.manaCostRightStr) { + symbols.add(symbol); + } + return symbols; } public int getManaValue() { @@ -991,14 +1033,8 @@ public class CardView extends SimpleCardView { } public String getColorIdentityStr() { - FilterMana colorInfo; - if (getOriginalCard() != null) { - // card - colorInfo = getOriginalCard().getColorIdentity(); - } else if (getOriginalToken() != null) { - // token - colorInfo = ManaUtil.getColorIdentity(getOriginalToken()); - } else { + FilterMana colorInfo = this.originalColorIdentity; + if (colorInfo != null) { colorInfo = new FilterMana(); } @@ -1285,20 +1321,24 @@ public class CardView extends SimpleCardView { return inViewerOnly; } - public Card getOriginalCard() { - if (this.originalObject instanceof Card) { - return (Card) this.originalObject; - } else { - return null; - } + public MageInt getOriginalPower() { + return this.originalPower; } - public Token getOriginalToken() { - if (this.originalObject instanceof Token) { - return (Token) this.originalObject; - } else { - return null; - } + public MageInt getOriginalToughness() { + return this.originalToughness; + } + + public UUID getOriginalId() { + return this.originalId; + } + + public boolean isOriginalACopy() { + return this.originalIsCopy; + } + + public boolean isOriginalACard() { + return this.originalIsCard; } public List getCardIcons() { diff --git a/Mage.Common/src/main/java/mage/view/PermanentView.java b/Mage.Common/src/main/java/mage/view/PermanentView.java index d9416d18513..7a3aaa2f13e 100644 --- a/Mage.Common/src/main/java/mage/view/PermanentView.java +++ b/Mage.Common/src/main/java/mage/view/PermanentView.java @@ -6,12 +6,12 @@ import mage.cards.Card; import mage.game.Game; import mage.game.permanent.Permanent; import mage.game.permanent.PermanentToken; -import mage.game.permanent.token.Token; import mage.players.Player; import java.util.ArrayList; import java.util.List; import java.util.UUID; +import java.util.stream.Collectors; /** * @author BetaSteward_at_googlemail.com @@ -142,6 +142,41 @@ public class PermanentView extends CardView { this.attachedControllerDiffers = attachedControllerDiffers; } + public PermanentView(PermanentView permanentView, Card card, UUID createdForPlayerId, Game game) { + super(permanentView); + this.controlled = permanentView.controlled; + this.tapped = permanentView.isTapped(); + this.flipped = permanentView.isFlipped(); + this.phasedIn = permanentView.isPhasedIn(); + this.summoningSickness = permanentView.summoningSickness; + this.damage = permanentView.damage; + this.attachments = permanentView.attachments.stream().collect(Collectors.toList()); + + boolean showFaceDownInfo = controlled || (game != null && game.hasEnded()); + + if (isToken()) { + original = new CardView(permanentView.original); + original.expansionSetCode = permanentView.original.getExpansionSetCode(); + expansionSetCode = permanentView.original.getExpansionSetCode(); + } else { + if (card != null && showFaceDownInfo) { + // face down card must be hidden from opponent, but shown on game end for all + original = new CardView(card.copy(), (Game) null); + } else { + original = null; + } + } + + this.copy = permanentView.copy; + this.nameOwner = permanentView.nameOwner; + this.nameController = permanentView.nameController; + this.attachedTo = permanentView.attachedTo; + this.morphed = permanentView.morphed; + this.manifested = permanentView.manifested; + this.attachedToPermanent = permanentView.attachedToPermanent; + this.attachedControllerDiffers = permanentView.attachedControllerDiffers; + } + public boolean isTapped() { return tapped; } diff --git a/Mage.Common/src/main/java/mage/view/StackAbilityView.java b/Mage.Common/src/main/java/mage/view/StackAbilityView.java index 77a6aa30313..f09049b5b0f 100644 --- a/Mage.Common/src/main/java/mage/view/StackAbilityView.java +++ b/Mage.Common/src/main/java/mage/view/StackAbilityView.java @@ -14,6 +14,8 @@ import mage.constants.CardType; import mage.constants.MageObjectType; import mage.game.Game; import mage.game.stack.StackAbility; +import mage.game.stack.StackObject; +import mage.target.Target; import mage.target.targetpointer.FixedTarget; import mage.target.targetpointer.TargetPointer; import mage.util.GameLog; @@ -21,8 +23,6 @@ import mage.util.GameLog; import java.util.ArrayList; import java.util.List; import java.util.UUID; -import mage.game.stack.StackObject; -import mage.target.Target; /** * @author BetaSteward_at_googlemail.com @@ -49,8 +49,8 @@ public class StackAbilityView extends CardView { this.subTypes = ability.getSubtype(game); this.superTypes = ability.getSuperType(game); this.color = ability.getColor(game); - this.manaCostLeftStr = String.join("", ability.getManaCostSymbols()); - this.manaCostRightStr = ""; + this.manaCostLeftStr = ability.getManaCostSymbols(); + this.manaCostRightStr = new ArrayList<>(); this.cardTypes = ability.getCardType(game); this.subTypes = ability.getSubtype(game); this.superTypes = ability.getSuperType(game); @@ -65,8 +65,8 @@ public class StackAbilityView extends CardView { tmpSourceCard.subTypes.clear(); tmpSourceCard.cardTypes.clear(); tmpSourceCard.cardTypes.add(CardType.CREATURE); - tmpSourceCard.manaCostLeftStr = ""; - tmpSourceCard.manaCostRightStr = ""; + tmpSourceCard.manaCostLeftStr = new ArrayList<>(); + tmpSourceCard.manaCostRightStr = new ArrayList<>(); tmpSourceCard.power = "2"; tmpSourceCard.toughness = "2"; nameToShow = "creature without name"; diff --git a/Mage.Server.Plugins/Mage.Player.AI/pom.xml b/Mage.Server.Plugins/Mage.Player.AI/pom.xml index 6b25e8db072..7daebd3d0ac 100644 --- a/Mage.Server.Plugins/Mage.Player.AI/pom.xml +++ b/Mage.Server.Plugins/Mage.Player.AI/pom.xml @@ -20,6 +20,11 @@ mage ${project.version} + + ${project.groupId} + mage-common + ${project.version} + ${project.groupId} mage-sets diff --git a/Mage.Server.Plugins/Mage.Player.AI/src/main/java/mage/player/ai/ComputerPlayer.java b/Mage.Server.Plugins/Mage.Player.AI/src/main/java/mage/player/ai/ComputerPlayer.java index 0960f21e7dc..06b1eb8ac59 100644 --- a/Mage.Server.Plugins/Mage.Player.AI/src/main/java/mage/player/ai/ComputerPlayer.java +++ b/Mage.Server.Plugins/Mage.Player.AI/src/main/java/mage/player/ai/ComputerPlayer.java @@ -16,6 +16,7 @@ import mage.abilities.mana.ManaOptions; import mage.cards.Card; import mage.cards.Cards; import mage.cards.CardsImpl; +import mage.cards.RateCard; import mage.cards.decks.Deck; import mage.cards.decks.DeckValidator; import mage.cards.decks.DeckValidatorFactory; @@ -34,7 +35,6 @@ import mage.filter.predicate.permanent.ControllerIdPredicate; import mage.game.Game; import mage.game.combat.CombatGroup; import mage.game.draft.Draft; -import mage.game.draft.RateCard; import mage.game.events.GameEvent; import mage.game.match.Match; import mage.game.permanent.Permanent; diff --git a/Mage.Server/src/main/java/mage/server/Main.java b/Mage.Server/src/main/java/mage/server/Main.java index dfe64ab26a5..9d6879d4324 100644 --- a/Mage.Server/src/main/java/mage/server/Main.java +++ b/Mage.Server/src/main/java/mage/server/Main.java @@ -6,7 +6,7 @@ import mage.cards.decks.DeckValidatorFactory; import mage.cards.repository.CardScanner; import mage.cards.repository.PluginClassloaderRegistery; import mage.cards.repository.RepositoryUtil; -import mage.game.draft.RateCard; +import mage.cards.RateCard; import mage.game.match.MatchType; import mage.game.tournament.TournamentType; import mage.interfaces.MageServer; diff --git a/Mage.Tests/src/test/java/org/mage/test/serverside/CardIconsTest.java b/Mage.Tests/src/test/java/org/mage/test/serverside/CardIconsTest.java index 0d0937c71ba..543e7e9ab45 100644 --- a/Mage.Tests/src/test/java/org/mage/test/serverside/CardIconsTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/serverside/CardIconsTest.java @@ -98,12 +98,12 @@ public class CardIconsTest extends CardTestPlayerBase { Assert.assertEquals("must have 2 cards in stack", 2, gameView.getStack().values().size()); CardView originalCardView = gameView.getStack().values() .stream() - .filter(c -> !c.getOriginalCard().isCopy()) + .filter(c -> !c.isOriginalACopy()) .findFirst() .get(); CardView copiedCardView = gameView.getStack().values() .stream() - .filter(c -> c.getOriginalCard().isCopy()) + .filter(c -> c.isOriginalACopy()) .findFirst() .get(); Assert.assertNotNull("stack must have original spell", originalCardView); diff --git a/Mage.Verify/src/test/java/mage/verify/VerifyCardDataTest.java b/Mage.Verify/src/test/java/mage/verify/VerifyCardDataTest.java index f5f38cfee4d..4088715f79c 100644 --- a/Mage.Verify/src/test/java/mage/verify/VerifyCardDataTest.java +++ b/Mage.Verify/src/test/java/mage/verify/VerifyCardDataTest.java @@ -29,7 +29,7 @@ import mage.filter.Filter; import mage.game.command.Dungeon; import mage.game.command.Plane; import mage.game.draft.DraftCube; -import mage.game.draft.RateCard; +import mage.cards.RateCard; import mage.game.permanent.token.Token; import mage.game.permanent.token.TokenImpl; import mage.game.permanent.token.custom.CreatureToken;