From 5f55c7c667ac7f17edf58a2e24009667d340fafe Mon Sep 17 00:00:00 2001 From: Oleg Agafonov Date: Mon, 8 May 2023 02:15:07 +0400 Subject: [PATCH] Tokens and command objects reworked (part 1 of 2): - fixed that copy effect doesn't restore original image after effect's end; - removed outdated availableImageSetCodes (all images auto-selected from tokens database now, related to #10139); - refactor command objects to use CommandObjectImpl; - refactor planes/emblems/etc objects to use MageObjectImpl, added copyable support; - refactor another game objects to remove some duplicated fields; --- .../collection/viewer/MageBook.java | 11 +- .../client/dialog/TestCardRenderDialog.java | 3 +- .../card/arcane/CardPanelRenderModeMTGO.java | 2 +- .../mage/card/arcane/ModernCardRenderer.java | 2 +- .../mage/plugins/card/images/ImageCache.java | 2 +- .../src/main/java/mage/view/CardView.java | 60 ++++---- .../src/main/java/mage/view/DungeonView.java | 2 +- .../src/main/java/mage/view/EmblemView.java | 13 +- .../src/main/java/mage/view/PlaneView.java | 13 +- .../main/java/mage/view/SimpleCardView.java | 3 + .../java/mage/server/util/SystemUtil.java | 3 +- .../mage/test/serverside/TokenImagesTest.java | 142 ++++++++++++++++-- .../org/mage/test/utils/DeckBuilderTest.java | 1 - .../java/mage/verify/VerifyCardDataTest.java | 13 +- Mage/src/main/java/mage/MageObject.java | 14 +- Mage/src/main/java/mage/MageObjectImpl.java | 46 +++++- .../src/main/java/mage/abilities/Ability.java | 2 +- .../main/java/mage/abilities/AbilityImpl.java | 2 +- .../effects/common/RollPlanarDieEffect.java | 3 +- .../mage/abilities/keyword/MorphAbility.java | 4 - .../mage/cards/AdventureCardSpellImpl.java | 5 - Mage/src/main/java/mage/cards/Card.java | 3 - Mage/src/main/java/mage/cards/CardImpl.java | 25 +-- .../cards/ModalDoubleFacesCardHalfImpl.java | 5 - Mage/src/main/java/mage/cards/Sets.java | 4 +- .../java/mage/cards/SplitCardHalfImpl.java | 5 - .../main/java/mage/cards/mock/MockCard.java | 4 +- .../java/mage/cards/mock/MockSplitCard.java | 1 - .../mage/cards/repository/CardRepository.java | 4 +- .../cards/repository/TokenRepository.java | 28 ++++ Mage/src/main/java/mage/game/Game.java | 2 +- Mage/src/main/java/mage/game/GameImpl.java | 12 +- .../java/mage/game/command/CommandObject.java | 4 - .../mage/game/command/CommandObjectImpl.java | 92 ++++++++++++ .../java/mage/game/command/Commander.java | 32 +--- .../main/java/mage/game/command/Dungeon.java | 61 +------- .../main/java/mage/game/command/Emblem.java | 95 +++--------- .../main/java/mage/game/command/Plane.java | 74 +++------ .../mage/game/permanent/PermanentCard.java | 5 +- .../mage/game/permanent/PermanentImpl.java | 14 +- .../mage/game/permanent/PermanentToken.java | 28 +--- Mage/src/main/java/mage/game/stack/Spell.java | 45 ++++-- .../java/mage/game/stack/StackAbility.java | 51 ++++--- Mage/src/main/java/mage/util/CardUtil.java | 51 ++----- Mage/src/main/resources/tokens-database.txt | 3 +- 45 files changed, 517 insertions(+), 477 deletions(-) create mode 100644 Mage/src/main/java/mage/game/command/CommandObjectImpl.java 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 d8d162e26f..670c04c474 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 @@ -241,9 +241,8 @@ public class MageBook extends JComponent { Constructor cons = c.getConstructor(); Object newToken = cons.newInstance(); if (newToken instanceof Token) { - ((Token) newToken).setOriginalExpansionSetCode(currentSet); - ((Token) newToken).setExpansionSetCodeForImage(currentSet); - ((Token) newToken).setTokenType(token.getImageNumber()); // must be called after set code, so it keep the type + ((Token) newToken).setExpansionSetCode(currentSet); + ((Token) newToken).setImageNumber(token.getImageNumber()); res.add(newToken); } } catch (Exception e) { @@ -262,7 +261,7 @@ public class MageBook extends JComponent { Constructor cons = c.getConstructor(); Object newEmblem = cons.newInstance(); if (newEmblem instanceof Emblem) { - ((Emblem) newEmblem).setExpansionSetCodeForImage(currentSet); + ((Emblem) newEmblem).setExpansionSetCode(currentSet); res.add(newEmblem); } } catch (Exception e) { @@ -281,7 +280,7 @@ public class MageBook extends JComponent { Constructor cons = c.getConstructor(); Object newPlane = cons.newInstance(); if (newPlane instanceof Plane) { - ((Plane) newPlane).setExpansionSetCodeForImage(currentSet); + ((Plane) newPlane).setExpansionSetCode(currentSet); res.add(newPlane); } } catch (Exception e) { @@ -300,7 +299,7 @@ public class MageBook extends JComponent { Constructor cons = c.getConstructor(); Object newDungeon = cons.newInstance(); if (newDungeon instanceof Dungeon) { - ((Dungeon) newDungeon).setExpansionSetCodeForImage(currentSet); + ((Dungeon) newDungeon).setExpansionSetCode(currentSet); res.add(newDungeon); } } catch (Exception e) { 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 7fa6f052c4..4646b06c5c 100644 --- a/Mage.Client/src/main/java/mage/client/dialog/TestCardRenderDialog.java +++ b/Mage.Client/src/main/java/mage/client/dialog/TestCardRenderDialog.java @@ -213,8 +213,7 @@ public class TestCardRenderDialog extends MageDialog { private CardView createToken(Game game, UUID controllerId, Token token, String code, int damage, boolean tapped, boolean transformed) { Token sourceToken = token.copy(); - sourceToken.setExpansionSetCodeForImage(code); - sourceToken.setOriginalExpansionSetCode(code); + sourceToken.setExpansionSetCode(code); PermanentToken perm = new PermanentToken(sourceToken, controllerId, game); Set cardsList = new HashSet<>(); diff --git a/Mage.Client/src/main/java/org/mage/card/arcane/CardPanelRenderModeMTGO.java b/Mage.Client/src/main/java/org/mage/card/arcane/CardPanelRenderModeMTGO.java index 655b45840c..d14144e850 100644 --- a/Mage.Client/src/main/java/org/mage/card/arcane/CardPanelRenderModeMTGO.java +++ b/Mage.Client/src/main/java/org/mage/card/arcane/CardPanelRenderModeMTGO.java @@ -131,7 +131,7 @@ public class CardPanelRenderModeMTGO extends CardPanel { sb.append(this.view.getLoyalty()); sb.append(this.view.getDefense()); sb.append(this.view.getColor().toString()); - sb.append(this.view.getType()); + sb.append(this.view.getImageNumber()); sb.append(this.view.getExpansionSetCode()); for (CardType type : this.view.getCardTypes()) { sb.append((char) type.ordinal()); 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 cdf4e2f13d..df43ab5e01 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 @@ -369,7 +369,7 @@ public class ModernCardRenderer extends CardRenderer { } private float getTypeLineYFrac() { - if (cardView.isToken() && cardView.getCardNumber() == null) { + if (cardView.isToken() && cardView.getCardNumber().isEmpty()) { return TYPE_LINE_Y_FRAC_TOKEN; } else if (cardView.getFrameStyle().isFullArt()) { return TYPE_LINE_Y_FRAC_FULL_ART; diff --git a/Mage.Client/src/main/java/org/mage/plugins/card/images/ImageCache.java b/Mage.Client/src/main/java/org/mage/plugins/card/images/ImageCache.java index 55fc80ff2f..45822b850b 100644 --- a/Mage.Client/src/main/java/org/mage/plugins/card/images/ImageCache.java +++ b/Mage.Client/src/main/java/org/mage/plugins/card/images/ImageCache.java @@ -344,7 +344,7 @@ public final class ImageCache { private static String getKey(CardView card, String cardName, int imageSize) { return (card.isToken() ? cardName.replace(" Token", "") : cardName) + '#' + card.getExpansionSetCode() - + '#' + card.getType() + + '#' + card.getImageNumber() + '#' + card.getCardNumber() + '#' + imageSize + (card.getUsesVariousArt() ? "#usesVariousArt" : ""); diff --git a/Mage.Common/src/main/java/mage/view/CardView.java b/Mage.Common/src/main/java/mage/view/CardView.java index 8419efd239..ba1988a9ef 100644 --- a/Mage.Common/src/main/java/mage/view/CardView.java +++ b/Mage.Common/src/main/java/mage/view/CardView.java @@ -52,7 +52,7 @@ public class CardView extends SimpleCardView { protected UUID parentId; @Expose - protected String name; + protected String name; // TODO: remove duplicated field name/displayName??? @Expose protected String displayName; @Expose @@ -88,7 +88,7 @@ public class CardView extends SimpleCardView { protected boolean isToken; protected CardView ability; - protected int type; + protected int imageNumber; protected boolean transformable; // can toggle one card side to another (transformable cards, modal double faces) protected CardView secondCardFace; @@ -182,6 +182,10 @@ public class CardView extends SimpleCardView { this.subTypes = new SubTypes(cardView.subTypes); this.superTypes = cardView.superTypes; + this.expansionSetCode = cardView.expansionSetCode; + this.cardNumber = cardView.cardNumber; + this.imageNumber = cardView.imageNumber; + this.color = cardView.color.copy(); this.frameColor = cardView.frameColor.copy(); this.frameStyle = cardView.frameStyle; @@ -195,7 +199,6 @@ public class CardView extends SimpleCardView { this.abilityType = cardView.abilityType; this.isToken = cardView.isToken; this.ability = cardView.ability; // reference, not copy - this.type = cardView.type; this.transformable = cardView.transformable; this.secondCardFace = cardView.secondCardFace == null ? null : new CardView(cardView.secondCardFace); @@ -281,6 +284,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.imageNumber = card.getImageNumber(); // no information available for face down cards as long it's not a controlled face down morph card // TODO: Better handle this in Framework (but currently I'm not sure how to do it there) LevelX2 @@ -305,6 +309,7 @@ public class CardView extends SimpleCardView { if (!showFaceUp) { this.fillEmpty(card, controlled); if (card instanceof Spell) { + // TODO: add face down image here??? // special handling for casting of Morph cards if (controlled) { this.name = card.getName(); @@ -391,7 +396,7 @@ public class CardView extends SimpleCardView { this.manaCostRightStr = ""; } - this.name = card.getImageName(); + this.name = card.getName(); this.displayName = card.getName(); this.displayFullName = fullCardName; this.rules = new ArrayList<>(card.getRules(game)); @@ -483,19 +488,7 @@ public class CardView extends SimpleCardView { this.isToken = true; this.mageObjectType = MageObjectType.TOKEN; this.rarity = Rarity.COMMON; - boolean originalCardNumberIsNull = ((PermanentToken) card).getToken().getOriginalCardNumber() == null; - if (!originalCardNumberIsNull && !"0".equals(((PermanentToken) card).getToken().getOriginalCardNumber())) { - // a token copied from permanent - this.expansionSetCode = ((PermanentToken) card).getToken().getOriginalExpansionSetCode(); - this.cardNumber = ((PermanentToken) card).getToken().getOriginalCardNumber(); - } else { - // a created token - this.expansionSetCode = card.getExpansionSetCode(); - } - // - // set code and card number for token copies to get the image this.rules = new ArrayList<>(card.getRules(game)); - this.type = ((PermanentToken) card).getToken().getTokenType(); } else { this.rarity = card.getRarity(); this.isToken = false; @@ -612,9 +605,10 @@ public class CardView extends SimpleCardView { } public CardView(MageObject object, Game game) { - super(object.getId(), "", "0", false, true); + super(object.getId(), object.getExpansionSetCode(), object.getCardNumber(), false, true); this.originalObject = object; + this.imageNumber = object.getImageNumber(); this.name = object.getName(); this.displayName = object.getName(); this.displayFullName = object.getName(); @@ -641,9 +635,7 @@ public class CardView extends SimpleCardView { this.mageObjectType = MageObjectType.TOKEN; PermanentToken permanentToken = (PermanentToken) object; this.rarity = Rarity.COMMON; - this.expansionSetCode = permanentToken.getExpansionSetCode(); this.rules = new ArrayList<>(permanentToken.getRules(game)); - this.type = permanentToken.getToken().getTokenType(); } else if (object instanceof Emblem) { this.mageObjectType = MageObjectType.EMBLEM; Emblem emblem = (Emblem) object; @@ -675,9 +667,6 @@ public class CardView extends SimpleCardView { this.rarity = Rarity.SPECIAL; this.rules = new ArrayList<>(); this.rules.add(stackAbility.getRule()); - if (stackAbility.getZone() == Zone.COMMAND) { - this.expansionSetCode = stackAbility.getExpansionSetCode(); - } } // Frame color this.frameColor = object.getFrameColor(game).copy(); @@ -706,6 +695,8 @@ public class CardView extends SimpleCardView { // emblem images are always with common (black) symbol this.frameStyle = FrameStyle.M15_NORMAL; this.expansionSetCode = emblem.getExpansionSetCode(); + this.cardNumber = ""; + this.imageNumber = 0; this.rarity = Rarity.COMMON; } @@ -722,6 +713,8 @@ public class CardView extends SimpleCardView { // emblem images are always with common (black) symbol this.frameStyle = FrameStyle.M15_NORMAL; this.expansionSetCode = dungeon.getExpansionSetCode(); + this.cardNumber = ""; + this.imageNumber = 0; this.rarity = Rarity.COMMON; } @@ -739,6 +732,8 @@ public class CardView extends SimpleCardView { this.rotate = true; this.frameStyle = FrameStyle.M15_NORMAL; this.expansionSetCode = plane.getExpansionSetCode(); + this.cardNumber = ""; + this.imageNumber = 0; this.rarity = Rarity.COMMON; } @@ -754,7 +749,10 @@ public class CardView extends SimpleCardView { this.rules = new ArrayList<>(); this.rules.add(stackAbility.getRule(designation.getName())); this.frameStyle = FrameStyle.M15_NORMAL; - this.expansionSetCode = designation.getExpansionSetCodeForImage(); + this.cardNumber = designation.getCardNumber(); + this.expansionSetCode = designation.getExpansionSetCode(); + this.cardNumber = ""; + this.imageNumber = 0; this.rarity = Rarity.COMMON; } @@ -793,6 +791,7 @@ public class CardView extends SimpleCardView { this.rarity = Rarity.COMMON; this.expansionSetCode = ""; this.cardNumber = "0"; + this.imageNumber = 0; } else { this.rarity = card.getRarity(); } @@ -819,7 +818,6 @@ public class CardView extends SimpleCardView { super(token.getId(), "", "0", false); this.isToken = true; this.id = token.getId(); - this.expansionSetCode = token.getOriginalExpansionSetCode(); this.name = token.getName(); this.displayName = token.getName(); this.displayFullName = token.getName(); @@ -839,7 +837,11 @@ public class CardView extends SimpleCardView { this.manaCostLeftStr = String.join("", token.getManaCostSymbols()); this.manaCostRightStr = ""; this.rarity = Rarity.SPECIAL; - this.type = token.getTokenType(); + + // source object is a token, so no card number + this.expansionSetCode = token.getExpansionSetCode(); + this.cardNumber = token.getCardNumber(); + this.imageNumber = token.getImageNumber(); } protected final void addTargets(Targets targets, Effects effects, Ability source, Game game) { @@ -995,10 +997,6 @@ public class CardView extends SimpleCardView { return expansionSetCode; } - public void setExpansionSetCode(String expansionSetCode) { - this.expansionSetCode = expansionSetCode; - } - @Override public UUID getId() { return id; @@ -1135,8 +1133,8 @@ public class CardView extends SimpleCardView { return bandedCards; } - public int getType() { - return type; + public int getImageNumber() { + return imageNumber; } public MageObjectType getMageObjectType() { diff --git a/Mage.Common/src/main/java/mage/view/DungeonView.java b/Mage.Common/src/main/java/mage/view/DungeonView.java index 9f5af24312..fa4dbfe173 100644 --- a/Mage.Common/src/main/java/mage/view/DungeonView.java +++ b/Mage.Common/src/main/java/mage/view/DungeonView.java @@ -21,7 +21,7 @@ public class DungeonView implements CommandObjectView, Serializable { public DungeonView(Dungeon dungeon) { this.id = dungeon.getId(); this.name = dungeon.getName(); - this.expansionSetCode = dungeon.getExpansionSetCodeForImage(); + this.expansionSetCode = dungeon.getExpansionSetCode(); this.rules = dungeon.getRules(); } diff --git a/Mage.Common/src/main/java/mage/view/EmblemView.java b/Mage.Common/src/main/java/mage/view/EmblemView.java index fe232761b2..774d607842 100644 --- a/Mage.Common/src/main/java/mage/view/EmblemView.java +++ b/Mage.Common/src/main/java/mage/view/EmblemView.java @@ -19,21 +19,10 @@ public class EmblemView implements CommandObjectView, Serializable { protected List rules; protected PlayableObjectStats playableStats = new PlayableObjectStats(); - public EmblemView(Emblem emblem, Card sourceCard) { - this.id = emblem.getId(); - this.name = "Emblem " + sourceCard.getName(); - if (emblem.getExpansionSetCodeForImage() == null) { - this.expansionSetCode = sourceCard.getExpansionSetCode(); - } else { - this.expansionSetCode = emblem.getExpansionSetCodeForImage(); - } - this.rules = emblem.getAbilities().getRules(sourceCard.getName()); - } - public EmblemView(Emblem emblem) { this.id = emblem.getId(); this.name = emblem.getName(); - this.expansionSetCode = emblem.getExpansionSetCodeForImage(); + this.expansionSetCode = emblem.getExpansionSetCode(); this.rules = emblem.getAbilities().getRules(emblem.getName()); } diff --git a/Mage.Common/src/main/java/mage/view/PlaneView.java b/Mage.Common/src/main/java/mage/view/PlaneView.java index 5dd32260e9..4698c33f14 100644 --- a/Mage.Common/src/main/java/mage/view/PlaneView.java +++ b/Mage.Common/src/main/java/mage/view/PlaneView.java @@ -19,21 +19,10 @@ public class PlaneView implements CommandObjectView, Serializable { protected List rules; protected PlayableObjectStats playableStats = new PlayableObjectStats(); - public PlaneView(Plane plane, Card sourceCard) { - this.id = plane.getId(); - this.name = "Plane " + sourceCard.getName(); - if (plane.getExpansionSetCodeForImage() == null) { - this.expansionSetCode = sourceCard.getExpansionSetCode(); - } else { - this.expansionSetCode = plane.getExpansionSetCodeForImage(); - } - this.rules = plane.getAbilities().getRules(sourceCard.getName()); - } - public PlaneView(Plane plane) { this.id = plane.getId(); this.name = plane.getName(); - this.expansionSetCode = plane.getExpansionSetCodeForImage(); + this.expansionSetCode = plane.getExpansionSetCode(); this.rules = plane.getAbilities().getRules(plane.getName()); } diff --git a/Mage.Common/src/main/java/mage/view/SimpleCardView.java b/Mage.Common/src/main/java/mage/view/SimpleCardView.java index d9b45476e8..77ef680ecd 100644 --- a/Mage.Common/src/main/java/mage/view/SimpleCardView.java +++ b/Mage.Common/src/main/java/mage/view/SimpleCardView.java @@ -7,9 +7,12 @@ import java.io.Serializable; import java.util.UUID; /** + * GUI: basic class for all card/object related views + * * @author BetaSteward_at_googlemail.com */ public class SimpleCardView implements Serializable, SelectableObjectView { + @Expose protected UUID id; protected String expansionSetCode; diff --git a/Mage.Server/src/main/java/mage/server/util/SystemUtil.java b/Mage.Server/src/main/java/mage/server/util/SystemUtil.java index 28b3b39fe0..3eb7ce464a 100644 --- a/Mage.Server/src/main/java/mage/server/util/SystemUtil.java +++ b/Mage.Server/src/main/java/mage/server/util/SystemUtil.java @@ -686,8 +686,7 @@ public final class SystemUtil { Planes planeType = Planes.fromClassName(planeClassName); Plane plane = Plane.createPlane(planeType); if (plane != null) { - plane.setControllerId(player.getId()); - game.addPlane(plane, null, player.getId()); + game.addPlane(plane, player.getId()); return true; } return false; diff --git a/Mage.Tests/src/test/java/org/mage/test/serverside/TokenImagesTest.java b/Mage.Tests/src/test/java/org/mage/test/serverside/TokenImagesTest.java index e7330ea81d..6e7e90e2a5 100644 --- a/Mage.Tests/src/test/java/org/mage/test/serverside/TokenImagesTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/serverside/TokenImagesTest.java @@ -1,5 +1,6 @@ package org.mage.test.serverside; +import mage.MageObject; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.mana.ManaCostsImpl; @@ -9,6 +10,7 @@ import mage.cards.repository.TokenRepository; import mage.constants.PhaseStep; import mage.constants.Zone; import mage.game.permanent.PermanentToken; +import mage.game.permanent.token.HumanToken; import mage.game.permanent.token.SoldierToken; import mage.game.permanent.token.Token; import mage.game.permanent.token.TokenImpl; @@ -24,6 +26,7 @@ import org.junit.Test; import org.mage.test.serverside.base.CardTestPlayerBase; import java.util.*; +import java.util.concurrent.atomic.AtomicInteger; import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.stream.Collectors; @@ -148,7 +151,7 @@ public class TokenImagesTest extends CardTestPlayerBase { Assert.assertNotNull("must have set code", card.getExpansionSetCode()); Assert.assertEquals("must have same set codes in all fields", card.getExpansionSetCode(), - ((PermanentToken) card).getToken().getOriginalExpansionSetCode() + ((PermanentToken) card).getToken().getExpansionSetCode() ); String realCode = card.getExpansionSetCode(); realServerStats.computeIfAbsent(realCode, code -> new ArrayList<>()); @@ -225,7 +228,7 @@ public class TokenImagesTest extends CardTestPlayerBase { // token as card like Embalm ability must have card number, so it will link to card's image instead token's image boolean hasCardNumbers = !realList.isEmpty() && realList .stream() - .mapToInt(card -> card.getCardNumber() == null ? 0 : CardUtil.parseCardNumberAsInt(card.getCardNumber())) + .mapToInt(card -> card.getCardNumber().isEmpty() ? 0 : CardUtil.parseCardNumberAsInt(card.getCardNumber())) .allMatch(x -> x > 0); if (mustStoreAsCard != hasCardNumbers) { isFine = false; @@ -257,13 +260,14 @@ public class TokenImagesTest extends CardTestPlayerBase { } } - private void assert_TokenTypes(String tokenName, int needTokenTypes) { + private void assert_TokenImageNumber(String tokenName, List needUniqueImages) { Set serverStats = currentGame.getBattlefield().getAllPermanents() .stream() .filter(card -> card.getName().equals(tokenName)) + .filter(card -> card instanceof PermanentToken) .sorted(Comparator.comparing(Card::getExpansionSetCode)) .map(card -> (PermanentToken) card) - .map(perm -> perm.getToken().getTokenType()) + .map(perm -> perm.getToken().getImageNumber()) .collect(Collectors.toSet()); GameView gameView = new GameView(currentGame.getState(), currentGame, playerA.getId(), null); @@ -277,13 +281,15 @@ public class TokenImagesTest extends CardTestPlayerBase { .stream() .filter(card -> card.getName().equals(tokenName)) .sorted(Comparator.comparing(CardView::getExpansionSetCode)) - .map(CardView::getType) + .map(CardView::getImageNumber) .collect(Collectors.toSet()); // server and client sides must have same data - Assert.assertEquals(serverStats.size(), clientStats.size()); - Assert.assertEquals(needTokenTypes, serverStats.size()); - Assert.assertEquals(needTokenTypes, clientStats.size()); + String imagesNeed = needUniqueImages.stream().sorted().map(Object::toString).collect(Collectors.joining(", ")); + String imagesServer = serverStats.stream().sorted().map(Object::toString).collect(Collectors.joining(", ")); + String imagesClient = clientStats.stream().sorted().map(Object::toString).collect(Collectors.joining(", ")); + Assert.assertEquals(imagesNeed, imagesServer); + Assert.assertEquals(imagesNeed, imagesClient); } @Test @@ -310,7 +316,7 @@ public class TokenImagesTest extends CardTestPlayerBase { // x2 tokens assert_MemorialToGlory(20, "40K=40"); - assert_TokenTypes("Soldier Token", 3); // 40K set contains 3 diffrent soldiers + assert_TokenImageNumber("Soldier Token", Arrays.asList(1, 2, 3)); // 40K set contains 3 diffrent soldiers } @Test @@ -355,12 +361,26 @@ public class TokenImagesTest extends CardTestPlayerBase { activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "create ten"); waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); + // workaround to find a real image number (tokens get random image on put to battlefield) + AtomicInteger realImageNumber = new AtomicInteger(0); + runCode("after", 1, PhaseStep.PRECOMBAT_MAIN, playerA, (info, player, game) -> { + PermanentToken token = game.getBattlefield().getAllPermanents() + .stream() + .filter(p -> p instanceof PermanentToken) + .map(p -> (PermanentToken) p) + .findFirst() + .orElse(null); + Assert.assertNotNull(token); + Assert.assertTrue(token.getImageNumber() >= 1 && token.getImageNumber() <= 3); + realImageNumber.set(token.getImageNumber()); + }); + setStrictChooseMode(true); setStopAt(1, PhaseStep.END_TURN); execute(); assertPermanentCount(playerA, 1 + 10); // 1 test card + 10 tokens - assert_TokenTypes("Soldier Token", 1); // one ability's call must generate tokens with same image + assert_TokenImageNumber("Soldier Token", Arrays.asList(realImageNumber.get())); // one ability's call must generate tokens with same image assert_Inner("test", 0, 0, 1, "Soldier Token", 10, false, "40K=10"); } @@ -430,6 +450,108 @@ public class TokenImagesTest extends CardTestPlayerBase { "Construct Token", 2, false, "MED=2"); } + @Test + public void test_TokenExists_CopyMustGetSameImageNumber() { + Ability ability = new SimpleActivatedAbility( + Zone.ALL, + new CreateTokenEffect(new HumanToken(), 10), + new ManaCostsImpl<>("") + ); + addCustomCardWithAbility("MOC-test", playerA, ability); // MOC contains only 1 token with image number 2 + // + // You may have Vesuvan Doppelganger enter the battlefield as a copy of any creature on the battlefield + addCard(Zone.HAND, playerA, "Vesuvan Doppelganger", 1); // {3}{U}{U} + addCard(Zone.BATTLEFIELD, playerA, "Island", 5); + + // create tokens + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "create ten"); + waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); + checkPermanentCount("prepare", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Human Token", 10); + // copy token + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Vesuvan Doppelganger"); + setChoice(playerA, true); + setChoice(playerA, "Human Token"); + waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); + checkPermanentCount("after copy", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Human Token", 10 + 1); + + setStrictChooseMode(true); + setStopAt(1, PhaseStep.END_TURN); + execute(); + + assert_TokenImageNumber("Human Token", Arrays.asList(2)); // one ability's call must generate tokens with same image + assert_Inner("test", 0, 0, 1, + "Human Token", 10, false, "MOC=10"); + } + + @Test + public void test_TokenExists_CopyEffectMustRestoreOldImageAfterEnd() { + // check a copy effect for: + // - a: card + // - b: token + // - c: token for card + + // {3}{U}{U} + // Echoing Equation + // Choose target creature you control. Each other creature you control becomes a copy of it until end of turn, except those creatures aren’t legendary if the chosen creature is legendary. + addCard(Zone.HAND, playerA, "STX-Augmenter Pugilist", 1); + addCard(Zone.BATTLEFIELD, playerA, "Island", 5); + addCard(Zone.BATTLEFIELD, playerA, "ICE-Balduvian Bears", 1); + // + // a: card + addCard(Zone.BATTLEFIELD, playerA, "NEC-Silver Myr", 1); + // + // b: token + prepareCards_TheHive("10E=1"); + // + // - c: token for card + // {2}{U} + // Choose target artifact creature you control. For each creature chosen this way, create a token that's a copy of it. + addCard(Zone.HAND, playerA, "BRC-March of Progress", 1); + addCard(Zone.BATTLEFIELD, playerA, "Island", 3); + + // prepare b: token + activate_TheHive(1); + + // prepare c: token for card + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "March of Progress"); + addTarget(playerA, "Silver Myr"); + waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); + + // check prepared data + checkPermanentCount("prepare", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Silver Myr", 2); // card + token + checkPermanentCount("prepare", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Wasp", 1); + + // copy bear + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Echoing Equation"); + addTarget(playerA, "Balduvian Bears"); + waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); + // must get 1 original card + 3 copies (1 from card, 1 from copy of card, 1 from token) + checkPermanentCount("after copy start", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Balduvian Bears", 4); + runCode("after copy start", 1, PhaseStep.PRECOMBAT_MAIN, playerA, (info, player, game) -> { + Set usedSetCodes = game.getBattlefield().getAllPermanents() + .stream() + .filter(MageObject::isCopy) + .map(Card::getExpansionSetCode) + .collect(Collectors.toSet()); + Assert.assertEquals(1, usedSetCodes.size()); + Assert.assertEquals("ICE", usedSetCodes.stream().findFirst().orElse(null)); + }); + + setStrictChooseMode(true); + setStopAt(3, PhaseStep.END_TURN); + execute(); + + // end of copy - must get original images + assertPermanentCount(playerA, "Balduvian Bears", 1); + assertPermanentCount(playerA, "Silver Myr", 2); // card + token + assertTokenCount(playerA, "Silver Myr", 1); + assertPermanentCount(playerA, "Wasp", 1); + assert_Inner("Silver Myr", 0, 0, 2, + "Silver Myr", 1, true, "NEC=1"); + assert_Inner("", 0, 0, 0, + "Wasp", 1, false, "10E=1"); + } + @Test @Ignore // TODO: implement auto-generate creature token images from public tokens (by name, type, color, PT, abilities) diff --git a/Mage.Tests/src/test/java/org/mage/test/utils/DeckBuilderTest.java b/Mage.Tests/src/test/java/org/mage/test/utils/DeckBuilderTest.java index 8abdc5abc3..70ac9430c5 100644 --- a/Mage.Tests/src/test/java/org/mage/test/utils/DeckBuilderTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/utils/DeckBuilderTest.java @@ -56,7 +56,6 @@ public class DeckBuilderTest { public RandomArtifactCreature(UUID ownerId, int cardNumber, String name) { super(ownerId, new CardSetInfo(name, "MRD", String.valueOf(cardNumber), Rarity.COMMON), new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{1}"); - this.expansionSetCode = "MRD"; this.power = new MageInt(1); this.toughness = new MageInt(1); } diff --git a/Mage.Verify/src/test/java/mage/verify/VerifyCardDataTest.java b/Mage.Verify/src/test/java/mage/verify/VerifyCardDataTest.java index b2adc891ba..61eb761acd 100644 --- a/Mage.Verify/src/test/java/mage/verify/VerifyCardDataTest.java +++ b/Mage.Verify/src/test/java/mage/verify/VerifyCardDataTest.java @@ -1337,12 +1337,11 @@ public class VerifyCardDataTest { // CHECK: named tokens must not have Token in the name if (token.getDescription().contains("named") && token.getName().contains("Token")) { - if (token.getDescription().contains("card named")) { - // ignore ability text like Return a card named Deathpact Angel from - continue; + // ignore ability text like Return a card named Deathpact Angel from + if (!token.getDescription().contains("card named")) { + errorsList.add("Error: named token must not have Token in the name: " + + tokenClass.getName() + " - " + token.getName() + " - " + token.getDescription()); } - errorsList.add("Error: named token must not have Token in the name: " - + tokenClass.getName() + " - " + token.getName() + " - " + token.getDescription()); } } @@ -1462,10 +1461,6 @@ public class VerifyCardDataTest { if (errorsList.size() > 0) { Assert.fail("Found token errors: " + errorsList.size()); } - - // TODO: all token must have correct availableImageSetCodes (all sets with that token) - // Some sets have original card, but don't have token card at all. So you must use scryfall tokens list above to find - // all token's sets and compare with xmage } @Test diff --git a/Mage/src/main/java/mage/MageObject.java b/Mage/src/main/java/mage/MageObject.java index 8a5de9fe31..6b7f13b4d0 100644 --- a/Mage/src/main/java/mage/MageObject.java +++ b/Mage/src/main/java/mage/MageObject.java @@ -23,14 +23,18 @@ import java.util.Set; public interface MageObject extends MageItem, Serializable, Copyable { + String getExpansionSetCode(); + void setExpansionSetCode(String expansionSetCode); + + String getCardNumber(); + void setCardNumber(String cardNumber); + + Integer getImageNumber(); + void setImageNumber(Integer imageNumber); + String getName(); - String getIdName(); - String getLogName(); - - String getImageName(); - void setName(String name); default List getCardType() { diff --git a/Mage/src/main/java/mage/MageObjectImpl.java b/Mage/src/main/java/mage/MageObjectImpl.java index c82f5781ac..326a262a14 100644 --- a/Mage/src/main/java/mage/MageObjectImpl.java +++ b/Mage/src/main/java/mage/MageObjectImpl.java @@ -29,18 +29,26 @@ public abstract class MageObjectImpl implements MageObject { protected String name; protected ManaCosts manaCost; + protected ObjectColor color; protected ObjectColor frameColor; protected FrameStyle frameStyle; + + private String expansionSetCode = ""; + private String cardNumber = ""; + private int imageNumber = 0; + protected List cardType = new ArrayList<>(); protected SubTypes subtype = new SubTypes(); protected Set supertype = EnumSet.noneOf(SuperType.class); protected Abilities abilities; + protected String text; protected MageInt power; protected MageInt toughness; protected int startingLoyalty = -1; // -2 means X, -1 means none, 0 and up is normal protected int startingDefense = -1; // -2 means X, -1 means none, 0 and up is normal + protected boolean copy; protected MageObject copyFrom; // copied card INFO (used to call original adjusters) @@ -67,6 +75,9 @@ public abstract class MageObjectImpl implements MageObject { color = object.color.copy(); frameColor = object.frameColor.copy(); frameStyle = object.frameStyle; + expansionSetCode = object.expansionSetCode; + cardNumber = object.cardNumber; + imageNumber = object.imageNumber; power = object.power.copy(); toughness = object.toughness.copy(); startingLoyalty = object.startingLoyalty; @@ -99,11 +110,6 @@ public abstract class MageObjectImpl implements MageObject { return GameLog.getColoredObjectIdName(this); } - @Override - public String getImageName() { - return name; - } - @Override public void setName(String name) { this.name = name; @@ -233,6 +239,36 @@ public abstract class MageObjectImpl implements MageObject { return frameStyle; } + @Override + public String getExpansionSetCode() { + return expansionSetCode; + } + + @Override + public void setExpansionSetCode(String expansionSetCode) { + this.expansionSetCode = expansionSetCode; + } + + @Override + public String getCardNumber() { + return cardNumber; + } + + @Override + public void setCardNumber(String cardNumber) { + this.cardNumber = cardNumber; + } + + @Override + public Integer getImageNumber() { + return imageNumber; + } + + @Override + public void setImageNumber(Integer imageNumber) { + this.imageNumber = imageNumber; + } + @Override public ManaCosts getManaCost() { return manaCost; diff --git a/Mage/src/main/java/mage/abilities/Ability.java b/Mage/src/main/java/mage/abilities/Ability.java index 42b6ab715b..a2753500be 100644 --- a/Mage/src/main/java/mage/abilities/Ability.java +++ b/Mage/src/main/java/mage/abilities/Ability.java @@ -61,7 +61,7 @@ public interface Ability extends Controllable, Serializable { * @see Game#addTriggeredAbility(TriggeredAbility, GameEvent) * @see mage.game.GameImpl#addDelayedTriggeredAbility(mage.abilities.DelayedTriggeredAbility) */ - void newOriginalId(); + void newOriginalId(); // TODO: delete newOriginalId??? /** * Gets the {@link AbilityType} of this ability. diff --git a/Mage/src/main/java/mage/abilities/AbilityImpl.java b/Mage/src/main/java/mage/abilities/AbilityImpl.java index 6be4340c52..a721ae1c49 100644 --- a/Mage/src/main/java/mage/abilities/AbilityImpl.java +++ b/Mage/src/main/java/mage/abilities/AbilityImpl.java @@ -52,7 +52,7 @@ public abstract class AbilityImpl implements Ability { private static final List emptyAbilities = new ArrayList<>(); protected UUID id; - protected UUID originalId; + protected UUID originalId; // TODO: delete originalId??? protected AbilityType abilityType; protected UUID controllerId; protected UUID sourceId; diff --git a/Mage/src/main/java/mage/abilities/effects/common/RollPlanarDieEffect.java b/Mage/src/main/java/mage/abilities/effects/common/RollPlanarDieEffect.java index c47e0c3919..60bfe4094c 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/RollPlanarDieEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/RollPlanarDieEffect.java @@ -128,8 +128,7 @@ public class RollPlanarDieEffect extends OneShotEffect { try { if (plane != null && !planesVisited.contains(plane.getName())) { foundNextPlane = true; - plane.setControllerId(controller.getId()); - game.addPlane(plane, null, controller.getId()); + game.addPlane(plane, controller.getId()); } } catch (Exception ex) { } diff --git a/Mage/src/main/java/mage/abilities/keyword/MorphAbility.java b/Mage/src/main/java/mage/abilities/keyword/MorphAbility.java index 8897d2d29e..c1d9d1b43d 100644 --- a/Mage/src/main/java/mage/abilities/keyword/MorphAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/MorphAbility.java @@ -12,7 +12,6 @@ import mage.abilities.costs.mana.GenericManaCost; import mage.abilities.costs.mana.ManaCost; import mage.abilities.effects.common.continuous.BecomesFaceDownCreatureEffect; import mage.abilities.effects.common.continuous.BecomesFaceDownCreatureEffect.FaceDownType; -import mage.cards.Card; import mage.constants.CardType; import mage.constants.Rarity; import mage.game.Game; @@ -157,9 +156,6 @@ public class MorphAbility extends AlternativeSourceCostsImpl { targetObject.getManaCost().clear(); Token emptyImage = new EmptyToken(); - emptyImage.setOriginalExpansionSetCode(""); - emptyImage.setExpansionSetCodeForImage(""); - emptyImage.setOriginalCardNumber(""); // TODO: add morph image here? if (targetObject instanceof Permanent) { diff --git a/Mage/src/main/java/mage/cards/AdventureCardSpellImpl.java b/Mage/src/main/java/mage/cards/AdventureCardSpellImpl.java index 8e60f55793..2452438984 100644 --- a/Mage/src/main/java/mage/cards/AdventureCardSpellImpl.java +++ b/Mage/src/main/java/mage/cards/AdventureCardSpellImpl.java @@ -45,11 +45,6 @@ public class AdventureCardSpellImpl extends CardImpl implements AdventureCardSpe return adventureCardParent.getOwnerId(); } - @Override - public String getImageName() { - return adventureCardParent.getImageName(); - } - @Override public String getExpansionSetCode() { return adventureCardParent.getExpansionSetCode(); diff --git a/Mage/src/main/java/mage/cards/Card.java b/Mage/src/main/java/mage/cards/Card.java index 347dc12462..1cd68e065a 100644 --- a/Mage/src/main/java/mage/cards/Card.java +++ b/Mage/src/main/java/mage/cards/Card.java @@ -25,8 +25,6 @@ public interface Card extends MageObject { UUID getOwnerId(); - String getCardNumber(); - Rarity getRarity(); // null for tokens void setOwnerId(UUID ownerId); @@ -48,7 +46,6 @@ public interface Card extends MageObject { List getRules(Game game); // gets card rules + in game modifications - String getExpansionSetCode(); void checkForCountersToAdd(Permanent permanent, Ability source, Game game); void setFaceDown(boolean value, Game game); diff --git a/Mage/src/main/java/mage/cards/CardImpl.java b/Mage/src/main/java/mage/cards/CardImpl.java index 182523f63e..3099f47f52 100644 --- a/Mage/src/main/java/mage/cards/CardImpl.java +++ b/Mage/src/main/java/mage/cards/CardImpl.java @@ -40,8 +40,6 @@ public abstract class CardImpl extends MageObjectImpl implements Card { private static final Logger logger = Logger.getLogger(CardImpl.class); protected UUID ownerId; - protected String cardNumber; - protected String expansionSetCode; protected Rarity rarity; protected Class secondSideCardClazz; protected Class meldsWithClazz; @@ -59,12 +57,12 @@ public abstract class CardImpl extends MageObjectImpl implements Card { public CardImpl(UUID ownerId, CardSetInfo setInfo, CardType[] cardTypes, String costs) { this(ownerId, setInfo, cardTypes, costs, SpellAbilityType.BASE); } - public CardImpl(UUID ownerId, CardSetInfo setInfo, CardType[] cardTypes, String costs, SpellAbilityType spellAbilityType) { this(ownerId, setInfo.getName()); + this.rarity = setInfo.getRarity(); - this.cardNumber = setInfo.getCardNumber(); - this.expansionSetCode = setInfo.getExpansionSetCode(); + this.setExpansionSetCode(setInfo.getExpansionSetCode()); + this.setCardNumber(setInfo.getCardNumber()); this.cardType.addAll(Arrays.asList(cardTypes)); this.manaCost.load(costs); setDefaultColor(); @@ -104,6 +102,7 @@ public abstract class CardImpl extends MageObjectImpl implements Card { } protected CardImpl(UUID ownerId, String name) { + super(); this.ownerId = ownerId; this.name = name; } @@ -117,8 +116,6 @@ public abstract class CardImpl extends MageObjectImpl implements Card { public CardImpl(final CardImpl card) { super(card); ownerId = card.ownerId; - cardNumber = card.cardNumber; - expansionSetCode = card.expansionSetCode; rarity = card.rarity; secondSideCardClazz = card.secondSideCardClazz; @@ -199,11 +196,6 @@ public abstract class CardImpl extends MageObjectImpl implements Card { return ownerId; } - @Override - public String getCardNumber() { - return cardNumber; - } - @Override public Rarity getRarity() { return rarity; @@ -369,11 +361,6 @@ public abstract class CardImpl extends MageObjectImpl implements Card { abilities.setControllerId(ownerId); } - @Override - public String getExpansionSetCode() { - return expansionSetCode; - } - @Override public List getMana() { List mana = new ArrayList<>(); @@ -634,11 +621,11 @@ public abstract class CardImpl extends MageObjectImpl implements Card { // must be non strict search in any sets, not one set // example: if set contains only one card side // method used in cards database creating, so can't use repository here - ExpansionSet.SetCardInfo info = Sets.findCardByClass(cardClazz, expansionSetCode, cardNumber); + ExpansionSet.SetCardInfo info = Sets.findCardByClass(cardClazz, this.getExpansionSetCode(), this.getCardNumber()); if (info == null) { return null; } - return createCard(cardClazz, new CardSetInfo(info.getName(), expansionSetCode, info.getCardNumber(), info.getRarity(), info.getGraphicInfo())); + return createCard(cardClazz, new CardSetInfo(info.getName(), this.getExpansionSetCode(), info.getCardNumber(), info.getRarity(), info.getGraphicInfo())); } @Override diff --git a/Mage/src/main/java/mage/cards/ModalDoubleFacesCardHalfImpl.java b/Mage/src/main/java/mage/cards/ModalDoubleFacesCardHalfImpl.java index c6de77a716..1902fa38b5 100644 --- a/Mage/src/main/java/mage/cards/ModalDoubleFacesCardHalfImpl.java +++ b/Mage/src/main/java/mage/cards/ModalDoubleFacesCardHalfImpl.java @@ -36,11 +36,6 @@ public class ModalDoubleFacesCardHalfImpl extends CardImpl implements ModalDoubl return parentCard.getOwnerId(); } - @Override - public String getImageName() { - return name; - } - @Override public String getExpansionSetCode() { // TODO: own set code? diff --git a/Mage/src/main/java/mage/cards/Sets.java b/Mage/src/main/java/mage/cards/Sets.java index 8435e0ce7b..40943485f3 100644 --- a/Mage/src/main/java/mage/cards/Sets.java +++ b/Mage/src/main/java/mage/cards/Sets.java @@ -211,7 +211,7 @@ public class Sets extends HashMap { if (instance.containsKey(preferredSetCode)) { info = instance.get(preferredSetCode).findCardInfoByClass(clazz) .stream() - .filter(card -> preferredCardNumber == null || card.getCardNumber().equals(preferredCardNumber)) + .filter(card -> preferredCardNumber.isEmpty() || card.getCardNumber().equals(preferredCardNumber)) .findFirst() .orElse(null); } @@ -220,7 +220,7 @@ public class Sets extends HashMap { for (Map.Entry entry : instance.entrySet()) { info = entry.getValue().findCardInfoByClass(clazz) .stream() - .filter(card -> preferredCardNumber == null || card.getCardNumber().equals(preferredCardNumber)) + .filter(card -> preferredCardNumber.isEmpty() || card.getCardNumber().equals(preferredCardNumber)) .findFirst() .orElse(null); if (info != null) { diff --git a/Mage/src/main/java/mage/cards/SplitCardHalfImpl.java b/Mage/src/main/java/mage/cards/SplitCardHalfImpl.java index 28df4f572c..fde94050ea 100644 --- a/Mage/src/main/java/mage/cards/SplitCardHalfImpl.java +++ b/Mage/src/main/java/mage/cards/SplitCardHalfImpl.java @@ -31,11 +31,6 @@ public class SplitCardHalfImpl extends CardImpl implements SplitCardHalf { return splitCardParent.getOwnerId(); } - @Override - public String getImageName() { - return splitCardParent.getImageName(); - } - @Override public String getExpansionSetCode() { return splitCardParent.getExpansionSetCode(); diff --git a/Mage/src/main/java/mage/cards/mock/MockCard.java b/Mage/src/main/java/mage/cards/mock/MockCard.java index 4fd1d0560b..5364a79f39 100644 --- a/Mage/src/main/java/mage/cards/mock/MockCard.java +++ b/Mage/src/main/java/mage/cards/mock/MockCard.java @@ -40,8 +40,8 @@ public class MockCard extends CardImpl { public MockCard(CardInfo card) { super(null, card.getName()); - this.cardNumber = card.getCardNumber(); - this.expansionSetCode = card.getSetCode(); + this.setExpansionSetCode(card.getSetCode()); + this.setCardNumber(card.getCardNumber()); this.power = mageIntFromString(card.getPower()); this.toughness = mageIntFromString(card.getToughness()); this.rarity = card.getRarity(); diff --git a/Mage/src/main/java/mage/cards/mock/MockSplitCard.java b/Mage/src/main/java/mage/cards/mock/MockSplitCard.java index c5495ffb84..65c2c437fd 100644 --- a/Mage/src/main/java/mage/cards/mock/MockSplitCard.java +++ b/Mage/src/main/java/mage/cards/mock/MockSplitCard.java @@ -26,7 +26,6 @@ public class MockSplitCard extends SplitCard { join(card.getManaCosts(CardInfo.ManaCostSide.LEFT)), join(card.getManaCosts(CardInfo.ManaCostSide.RIGHT)), getSpellAbilityType(card)); - this.expansionSetCode = card.getSetCode(); this.power = mageIntFromString(card.getPower()); this.toughness = mageIntFromString(card.getToughness()); this.cardType = card.getTypes(); diff --git a/Mage/src/main/java/mage/cards/repository/CardRepository.java b/Mage/src/main/java/mage/cards/repository/CardRepository.java index 45b1f6e48f..c6183fdf1a 100644 --- a/Mage/src/main/java/mage/cards/repository/CardRepository.java +++ b/Mage/src/main/java/mage/cards/repository/CardRepository.java @@ -349,7 +349,7 @@ public enum CardRepository { } public CardInfo findPreferredCoreExpansionCard(String name) { - return findPreferredCoreExpansionCard(name, null); + return findPreferredCoreExpansionCard(name, ""); } public CardInfo findPreferredCoreExpansionCard(String name, String preferredSetCode) { @@ -368,7 +368,7 @@ public enum CardRepository { ExpansionInfo set = ExpansionRepository.instance.getSetByCode(cardinfo.getSetCode()); if (set != null) { - if ((preferredSetCode != null) && (preferredSetCode.equals(set.getCode()))) { + if (preferredSetCode.equals(set.getCode())) { return cardinfo; } diff --git a/Mage/src/main/java/mage/cards/repository/TokenRepository.java b/Mage/src/main/java/mage/cards/repository/TokenRepository.java index 8315e22cb9..590f65bc5b 100644 --- a/Mage/src/main/java/mage/cards/repository/TokenRepository.java +++ b/Mage/src/main/java/mage/cards/repository/TokenRepository.java @@ -1,5 +1,6 @@ package mage.cards.repository; +import mage.util.RandomUtil; import org.apache.log4j.Logger; import java.io.BufferedReader; @@ -275,4 +276,31 @@ public enum TokenRepository { return res; } + + /** + * Try to find random image info by related set code + * + * @param className full class name of the token or other object + * @param setCode primary set code for possible image + * @return + */ + public TokenInfo generateTokenInfoBySetCode(String className, String setCode) { + // search by set code + List possibleInfo = TokenRepository.instance.getByClassName(className) + .stream() + .filter(info -> info.getSetCode().equals(setCode)) + .collect(Collectors.toList()); + + // search by random set + if (possibleInfo.isEmpty()) { + possibleInfo = new ArrayList<>(TokenRepository.instance.getByClassName(className)); + } + + // also weill return diff image number for tokens + if (possibleInfo.size() > 0) { + return RandomUtil.randomFromCollection(possibleInfo); + } else { + return null; + } + } } diff --git a/Mage/src/main/java/mage/game/Game.java b/Mage/src/main/java/mage/game/Game.java index 0178445dfc..fd8813ae35 100644 --- a/Mage/src/main/java/mage/game/Game.java +++ b/Mage/src/main/java/mage/game/Game.java @@ -398,7 +398,7 @@ public interface Game extends MageItem, Serializable, Copyable { void addEmblem(Emblem emblem, MageObject sourceObject, UUID toPlayerId); - boolean addPlane(Plane plane, MageObject sourceObject, UUID toPlayerId); + boolean addPlane(Plane plane, UUID toPlayerId); void addCommander(Commander commander); diff --git a/Mage/src/main/java/mage/game/GameImpl.java b/Mage/src/main/java/mage/game/GameImpl.java index 0092e4228b..508bac1db8 100644 --- a/Mage/src/main/java/mage/game/GameImpl.java +++ b/Mage/src/main/java/mage/game/GameImpl.java @@ -1307,7 +1307,7 @@ public abstract class GameImpl implements Game { if (gameOptions.planeChase) { Plane plane = Plane.createRandomPlane(); plane.setControllerId(startingPlayerId); - addPlane(plane, null, startingPlayerId); + addPlane(plane, startingPlayerId); state.setPlaneChase(this, gameOptions.planeChase); } } @@ -1850,18 +1850,18 @@ public abstract class GameImpl implements Game { for (Ability ability : newEmblem.getAbilities()) { ability.setSourceId(newEmblem.getId()); } - state.addCommandObject(newEmblem); + + state.addCommandObject(newEmblem); // TODO: generate image for emblem here? } /** * @param plane - * @param sourceObject * @param toPlayerId controller and owner of the plane (may only be one * per game..) * @return boolean - whether the plane was added successfully or not */ @Override - public boolean addPlane(Plane plane, MageObject sourceObject, UUID toPlayerId) { + public boolean addPlane(Plane plane, UUID toPlayerId) { // Implementing planechase as if it were 901.15. Single Planar Deck Option // Here, can enforce the world plane restriction (the Grand Melee format may have some impact on this implementation) @@ -1872,7 +1872,7 @@ public abstract class GameImpl implements Game { } } Plane newPlane = plane.copy(); - newPlane.setSourceObject(sourceObject); + newPlane.setSourceObject(); newPlane.setControllerId(toPlayerId); newPlane.assignNewId(); newPlane.getAbilities().newId(); @@ -3160,7 +3160,7 @@ public abstract class GameImpl implements Game { addedAgain = true; Plane plane = Plane.createRandomPlane(); plane.setControllerId(aplayer.getId()); - addPlane(plane, null, aplayer.getId()); + addPlane(plane, aplayer.getId()); } } } diff --git a/Mage/src/main/java/mage/game/command/CommandObject.java b/Mage/src/main/java/mage/game/command/CommandObject.java index a2b596e5b2..8659aba37b 100644 --- a/Mage/src/main/java/mage/game/command/CommandObject.java +++ b/Mage/src/main/java/mage/game/command/CommandObject.java @@ -18,8 +18,4 @@ public interface CommandObject extends MageObject, Controllable { @Override CommandObject copy(); - - String getExpansionSetCodeForImage(); - - void setExpansionSetCodeForImage(String expansionSetCodeForImage); } diff --git a/Mage/src/main/java/mage/game/command/CommandObjectImpl.java b/Mage/src/main/java/mage/game/command/CommandObjectImpl.java new file mode 100644 index 0000000000..87c8175870 --- /dev/null +++ b/Mage/src/main/java/mage/game/command/CommandObjectImpl.java @@ -0,0 +1,92 @@ +package mage.game.command; + +import mage.game.permanent.token.TokenImpl; +import mage.util.GameLog; + +import java.util.UUID; + +/** + * @author JayDi85 + */ +public abstract class CommandObjectImpl implements CommandObject { + + private UUID id; + private String name = ""; + + private String expansionSetCode; + private String cardNumber; + private int imageNumber; + + public CommandObjectImpl(String name) { + this.id = UUID.randomUUID(); + this.name = name; + } + + protected CommandObjectImpl(final CommandObjectImpl object) { + this.id = object.id; + this.name = object.name; + this.expansionSetCode = object.expansionSetCode; + this.cardNumber = object.cardNumber; + this.imageNumber = object.imageNumber; + } + + @Override + public UUID getId() { + return this.id; + } + + @Override + public String getExpansionSetCode() { + return expansionSetCode; + } + + @Override + public void setExpansionSetCode(String expansionSetCode) { + this.expansionSetCode = expansionSetCode; + } + + @Override + public String getCardNumber() { + return cardNumber; + } + + @Override + public void setCardNumber(String cardNumber) { + this.cardNumber = cardNumber; + } + + @Override + public Integer getImageNumber() { + return imageNumber; + } + + @Override + public void setImageNumber(Integer imageNumber) { + this.imageNumber = imageNumber; + } + + @Override + public void assignNewId() { + this.id = UUID.randomUUID(); + } + + @Override + public String getName() { + return name; + } + + @Override + public void setName(String name) { + this.name = name; + } + + @Override + public String getIdName() { + return getName() + " [" + getId().toString().substring(0, 3) + ']'; + } + + @Override + public String getLogName() { + return GameLog.getColoredObjectIdName(this); + } +} diff --git a/Mage/src/main/java/mage/game/command/Commander.java b/Mage/src/main/java/mage/game/command/Commander.java index de1092a500..3fb4511e32 100644 --- a/Mage/src/main/java/mage/game/command/Commander.java +++ b/Mage/src/main/java/mage/game/command/Commander.java @@ -23,7 +23,7 @@ import java.util.List; import java.util.Set; import java.util.UUID; -public class Commander implements CommandObject { +public class Commander extends CommandObjectImpl { private final Card sourceObject; private boolean copy; @@ -31,6 +31,7 @@ public class Commander implements CommandObject { private final Abilities abilities = new AbilitiesImpl<>(); public Commander(Card card) { + super(card.getName()); this.sourceObject = card; // All abilities must be added to the game before usage. It adding by addCard and addCommandObject calls @@ -106,6 +107,7 @@ public class Commander implements CommandObject { } private Commander(final Commander commander) { + super(commander); this.sourceObject = commander.sourceObject.copy(); this.copy = commander.copy; this.copyFrom = (commander.copyFrom != null ? commander.copyFrom.copy() : null); @@ -127,10 +129,6 @@ public class Commander implements CommandObject { return sourceObject.getOwnerId(); } - @Override - public void assignNewId() { - } - @Override public CommandObject copy() { return new Commander(this); @@ -162,15 +160,6 @@ public class Commander implements CommandObject { return sourceObject.getName() + " [" + sourceObject.getId().toString().substring(0, 3) + ']'; } - @Override - public String getLogName() { - return GameLog.getColoredObjectIdName(this); - } - - @Override - public void setName(String name) { - } - @Override public List getCardType(Game game) { return sourceObject.getCardType(game); @@ -289,21 +278,6 @@ public class Commander implements CommandObject { return sourceObject.getId(); } - @Override - public String getImageName() { - return sourceObject.getImageName(); - } - - @Override - public String getExpansionSetCodeForImage() { - return sourceObject.getExpansionSetCode(); - } - - @Override - public void setExpansionSetCodeForImage(String expansionSetCodeForImage) { - throw new IllegalStateException("Can't change a set code of the commander, source card already has it"); - } - @Override public int getZoneChangeCounter(Game game) { return sourceObject.getZoneChangeCounter(game); diff --git a/Mage/src/main/java/mage/game/command/Dungeon.java b/Mage/src/main/java/mage/game/command/Dungeon.java index a7e8b438e5..54e41f12d2 100644 --- a/Mage/src/main/java/mage/game/command/Dungeon.java +++ b/Mage/src/main/java/mage/game/command/Dungeon.java @@ -35,7 +35,7 @@ import java.util.*; /** * @author TheElk801 */ -public class Dungeon implements CommandObject { +public class Dungeon extends CommandObjectImpl { private static final Set dungeonNames = new HashSet<>(); @@ -49,31 +49,24 @@ public class Dungeon implements CommandObject { private static final ObjectColor emptyColor = new ObjectColor(); private static final ManaCosts emptyCost = new ManaCostsImpl<>(); - private final String name; - private UUID id; private UUID controllerId; private boolean copy; private MageObject copyFrom; // copied card INFO (used to call original adjusters) private FrameStyle frameStyle; private final Abilities abilites = new AbilitiesImpl<>(); - private String expansionSetCodeForImage; private final List dungeonRooms = new ArrayList<>(); private DungeonRoom currentRoom = null; - public Dungeon(String name, String expansionSetCodeForImage) { - this.id = UUID.randomUUID(); - this.name = name; - this.expansionSetCodeForImage = expansionSetCodeForImage; + public Dungeon(String name) { + super(name); } public Dungeon(final Dungeon dungeon) { - this.id = dungeon.id; - this.name = dungeon.name; + super(dungeon); this.frameStyle = dungeon.frameStyle; this.controllerId = dungeon.controllerId; this.copy = dungeon.copy; this.copyFrom = (dungeon.copyFrom != null ? dungeon.copyFrom : null); - this.expansionSetCodeForImage = dungeon.expansionSetCodeForImage; this.copyRooms(dungeon); } @@ -91,7 +84,7 @@ public class Dungeon implements CommandObject { public void addRoom(DungeonRoom room) { this.dungeonRooms.add(room); - room.getRoomTriggeredAbility().setSourceId(id); + room.getRoomTriggeredAbility().setSourceId(this.getId()); this.abilites.add(room.getRoomTriggeredAbility()); } @@ -173,11 +166,6 @@ public class Dungeon implements CommandObject { return frameStyle; } - @Override - public void assignNewId() { - this.id = UUID.randomUUID(); - } - @Override public MageObject getSourceObject() { return null; @@ -214,30 +202,6 @@ public class Dungeon implements CommandObject { return this.copyFrom; } - @Override - public String getName() { - return name; - } - - @Override - public String getIdName() { - return getName() + " [" + getId().toString().substring(0, 3) + ']'; - } - - @Override - public String getLogName() { - return GameLog.getColoredObjectIdName(this); - } - - @Override - public String getImageName() { - return this.name; - } - - @Override - public void setName(String name) { - } - @Override public List getCardType(Game game) { return emptyList; @@ -326,26 +290,11 @@ public class Dungeon implements CommandObject { public void setStartingDefense(int startingDefense) { } - @Override - public UUID getId() { - return this.id; - } - @Override public Dungeon copy() { return new Dungeon(this); } - @Override - public String getExpansionSetCodeForImage() { - return expansionSetCodeForImage; - } - - @Override - public void setExpansionSetCodeForImage(String expansionSetCodeForImage) { - this.expansionSetCodeForImage = expansionSetCodeForImage; - } - @Override public int getZoneChangeCounter(Game game) { return 1; diff --git a/Mage/src/main/java/mage/game/command/Emblem.java b/Mage/src/main/java/mage/game/command/Emblem.java index a49d706fd3..0f70cb4c3f 100644 --- a/Mage/src/main/java/mage/game/command/Emblem.java +++ b/Mage/src/main/java/mage/game/command/Emblem.java @@ -13,11 +13,14 @@ import mage.abilities.effects.ContinuousEffect; import mage.abilities.effects.Effect; import mage.cards.Card; import mage.cards.FrameStyle; +import mage.cards.repository.TokenInfo; +import mage.cards.repository.TokenRepository; import mage.constants.CardType; import mage.constants.SubType; import mage.constants.SuperType; import mage.game.Game; import mage.game.events.ZoneChangeEvent; +import mage.game.permanent.token.TokenImpl; import mage.util.GameLog; import mage.util.RandomUtil; import mage.util.SubTypes; @@ -27,40 +30,31 @@ import java.util.*; /** * @author nantuko */ -public class Emblem implements CommandObject { +public abstract class Emblem extends CommandObjectImpl { private static final List emptyList = Collections.unmodifiableList(new ArrayList<>()); private static final ObjectColor emptyColor = new ObjectColor(); private static final ManaCosts emptyCost = new ManaCostsImpl<>(); - private String name = ""; - private UUID id; private UUID controllerId; private MageObject sourceObject; private boolean copy; private MageObject copyFrom; // copied card INFO (used to call original adjusters) private FrameStyle frameStyle; private Abilities abilites = new AbilitiesImpl<>(); - private String expansionSetCodeForImage = ""; - // list of set codes emblem images are available for - protected List availableImageSetCodes = new ArrayList<>(); - - public Emblem() { - this.id = UUID.randomUUID(); + public Emblem(String name) { + super(name); } public Emblem(final Emblem emblem) { - this.id = emblem.id; - this.name = emblem.name; + super(emblem); this.frameStyle = emblem.frameStyle; this.controllerId = emblem.controllerId; this.sourceObject = emblem.sourceObject; this.copy = emblem.copy; this.copyFrom = (emblem.copyFrom != null ? emblem.copyFrom : null); this.abilites = emblem.abilites.copy(); - this.expansionSetCodeForImage = emblem.expansionSetCodeForImage; - this.availableImageSetCodes = emblem.availableImageSetCodes; } @Override @@ -68,25 +62,18 @@ public class Emblem implements CommandObject { return frameStyle; } - @Override - public void assignNewId() { - this.id = UUID.randomUUID(); - } - public void setSourceObject(MageObject sourceObject) { this.sourceObject = sourceObject; - if (sourceObject instanceof Card) { - if (name.isEmpty()) { - name = sourceObject.getSubtype().toString(); - } - if (expansionSetCodeForImage.isEmpty()) { - expansionSetCodeForImage = ((Card) sourceObject).getExpansionSetCode(); - } - if (!availableImageSetCodes.isEmpty()) { - if (expansionSetCodeForImage.equals("") || !availableImageSetCodes.contains(expansionSetCodeForImage)) { - expansionSetCodeForImage = availableImageSetCodes.get(RandomUtil.nextInt(availableImageSetCodes.size())); - } - } + + // choose set code due source + TokenInfo foundInfo = TokenRepository.instance.generateTokenInfoBySetCode(this.getClass().getName(), sourceObject.getExpansionSetCode()); + if (foundInfo != null) { + this.setExpansionSetCode(foundInfo.getSetCode()); + this.setCardNumber(""); + this.setImageNumber(foundInfo.getImageNumber()); + } else { + // how-to fix: add emblem to the tokens-database + throw new IllegalArgumentException("Wrong code usage: can't find token info for the emblem: " + this.getClass().getName()); } } @@ -113,6 +100,9 @@ public class Emblem implements CommandObject { this.abilites.setControllerId(controllerId); } + @Override + abstract public Emblem copy(); + @Override public void setCopy(boolean isCopy, MageObject copyFrom) { this.copy = isCopy; @@ -129,31 +119,6 @@ public class Emblem implements CommandObject { return this.copyFrom; } - @Override - public String getName() { - return name; - } - - @Override - public String getIdName() { - return getName() + " [" + getId().toString().substring(0, 3) + ']'; - } - - @Override - public String getLogName() { - return GameLog.getColoredObjectIdName(this); - } - - @Override - public String getImageName() { - return this.name; - } - - @Override - public void setName(String name) { - this.name = name; - } - @Override public List getCardType(Game game) { return emptyList; @@ -242,26 +207,6 @@ public class Emblem implements CommandObject { public void setStartingDefense(int startingDefense) { } - @Override - public UUID getId() { - return this.id; - } - - @Override - public Emblem copy() { - return new Emblem(this); - } - - @Override - public String getExpansionSetCodeForImage() { - return expansionSetCodeForImage; - } - - @Override - public void setExpansionSetCodeForImage(String expansionSetCodeForImage) { - this.expansionSetCodeForImage = expansionSetCodeForImage; - } - @Override public int getZoneChangeCounter(Game game) { return 1; // Emblems can't move zones until now so return always 1 diff --git a/Mage/src/main/java/mage/game/command/Plane.java b/Mage/src/main/java/mage/game/command/Plane.java index 43d7c047a7..8ea5fa976f 100644 --- a/Mage/src/main/java/mage/game/command/Plane.java +++ b/Mage/src/main/java/mage/game/command/Plane.java @@ -13,6 +13,8 @@ import mage.abilities.effects.ContinuousEffect; import mage.abilities.effects.Effect; import mage.cards.Card; import mage.cards.FrameStyle; +import mage.cards.repository.TokenInfo; +import mage.cards.repository.TokenRepository; import mage.constants.CardType; import mage.constants.Planes; import mage.constants.SubType; @@ -29,29 +31,28 @@ import java.util.*; /** * @author spjspj */ -public class Plane implements CommandObject { +public abstract class Plane extends CommandObjectImpl { private static final List emptyList = Collections.unmodifiableList(new ArrayList<>()); private static final ObjectColor emptyColor = new ObjectColor(); private static final ManaCosts emptyCost = new ManaCostsImpl<>(); private Planes planeType = null; - private UUID id; + private UUID controllerId; private MageObject sourceObject; private boolean copy; private MageObject copyFrom; // copied card INFO (used to call original adjusters) private FrameStyle frameStyle; private Abilities abilites = new AbilitiesImpl<>(); - private String expansionSetCodeForImage = ""; public Plane() { - this.id = UUID.randomUUID(); + super(""); this.frameStyle = FrameStyle.M15_NORMAL; } public Plane(final Plane plane) { - this.id = plane.id; + super(plane); this.planeType = plane.planeType; this.frameStyle = plane.frameStyle; this.controllerId = plane.controllerId; @@ -59,7 +60,6 @@ public class Plane implements CommandObject { this.copy = plane.copy; this.copyFrom = (plane.copyFrom != null ? plane.copyFrom.copy() : null); this.abilites = plane.abilites.copy(); - this.expansionSetCodeForImage = plane.expansionSetCodeForImage; } @Override @@ -67,17 +67,18 @@ public class Plane implements CommandObject { return frameStyle; } - @Override - public void assignNewId() { - this.id = UUID.randomUUID(); - } + public void setSourceObject() { + this.sourceObject = null; - public void setSourceObject(MageObject sourceObject) { - this.sourceObject = sourceObject; - if (sourceObject instanceof Card) { - if (expansionSetCodeForImage.isEmpty()) { - expansionSetCodeForImage = ((Card) sourceObject).getExpansionSetCode(); - } + // choose set code due source + TokenInfo foundInfo = TokenRepository.instance.generateTokenInfoBySetCode(this.getClass().getName(), null); + if (foundInfo != null) { + this.setExpansionSetCode(foundInfo.getSetCode()); + this.setCardNumber(""); + this.setImageNumber(foundInfo.getImageNumber()); + } else { + // how-to fix: add plane to the tokens-database + throw new IllegalArgumentException("Wrong code usage: can't find token info for the plane: " + this.getClass().getName()); } } @@ -104,6 +105,9 @@ public class Plane implements CommandObject { this.abilites.setControllerId(controllerId); } + @Override + abstract public Plane copy(); + @Override public void setCopy(boolean isCopy, MageObject copyFrom) { this.copy = isCopy; @@ -125,21 +129,6 @@ public class Plane implements CommandObject { return planeType != null ? planeType.getFullName() : ""; } - @Override - public String getIdName() { - return getName() + " [" + getId().toString().substring(0, 3) + ']'; - } - - @Override - public String getLogName() { - return GameLog.getColoredObjectIdName(this); - } - - @Override - public String getImageName() { - return planeType != null ? planeType.getFullName() : ""; - } - @Override public void setName(String name) { throw new UnsupportedOperationException("Planes don't use setName, use setPlaneType instead"); @@ -241,29 +230,9 @@ public class Plane implements CommandObject { public void setStartingDefense(int startingDefense) { } - @Override - public UUID getId() { - return this.id; - } - - @Override - public Plane copy() { - return new Plane(this); - } - - @Override - public String getExpansionSetCodeForImage() { - return expansionSetCodeForImage; - } - - @Override - public void setExpansionSetCodeForImage(String expansionSetCodeForImage) { - this.expansionSetCodeForImage = expansionSetCodeForImage; - } - @Override public int getZoneChangeCounter(Game game) { - return 1; // Emblems can't move zones until now so return always 1 + return 1; // Planes can't move zones until now so return always 1 } @Override @@ -311,6 +280,7 @@ public class Plane implements CommandObject { Constructor cons = c.getConstructor(); Object plane = cons.newInstance(); if (plane instanceof Plane) { + // TODO: generate image for plane here? return (Plane) plane; } } catch (Exception ex) { diff --git a/Mage/src/main/java/mage/game/permanent/PermanentCard.java b/Mage/src/main/java/mage/game/permanent/PermanentCard.java index 20b8a70173..2341d5c09a 100644 --- a/Mage/src/main/java/mage/game/permanent/PermanentCard.java +++ b/Mage/src/main/java/mage/game/permanent/PermanentCard.java @@ -126,9 +126,10 @@ public class PermanentCard extends PermanentImpl { this.subtype.copyFrom(card.getSubtype()); this.supertype.clear(); this.supertype.addAll(card.getSuperType()); - this.expansionSetCode = card.getExpansionSetCode(); + + this.setExpansionSetCode(card.getExpansionSetCode()); + this.setCardNumber(card.getCardNumber()); this.rarity = card.getRarity(); - this.cardNumber = card.getCardNumber(); this.usesVariousArt = card.getUsesVariousArt(); if (card.getSecondCardFace() != null) { diff --git a/Mage/src/main/java/mage/game/permanent/PermanentImpl.java b/Mage/src/main/java/mage/game/permanent/PermanentImpl.java index affd3017a3..77d425e61c 100644 --- a/Mage/src/main/java/mage/game/permanent/PermanentImpl.java +++ b/Mage/src/main/java/mage/game/permanent/PermanentImpl.java @@ -186,7 +186,7 @@ public abstract class PermanentImpl extends CardImpl implements Permanent { @Override public String toString() { StringBuilder sb = threadLocalBuilder.get(); - sb.append(this.getName()).append('-').append(this.expansionSetCode); + sb.append(this.getName()).append('-').append(this.getExpansionSetCode()); if (copy) { sb.append(" [Copy]"); } @@ -1184,7 +1184,7 @@ public abstract class PermanentImpl extends CardImpl implements Permanent { @Override public boolean entersBattlefield(Ability source, Game game, Zone fromZone, boolean fireEvent) { controlledFromStartOfControllerTurn = false; - if (this.isFaceDown(game)) { // ?? add morphed/manifested here ?? + if (this.isFaceDown(game)) { // ?? add morphed/manifested here ??? // remove some attributes here, because first apply effects comes later otherwise abilities (e.g. color related) will unintended trigger MorphAbility.setPermanentToFaceDownCreature(this, this, game); } @@ -1782,16 +1782,6 @@ public abstract class PermanentImpl extends CardImpl implements Permanent { morphed = value; } - @Override - public void setCardNumber(String cardNumber) { - this.cardNumber = cardNumber; - } - - @Override - public void setExpansionSetCode(String expansionSetCode) { - this.expansionSetCode = expansionSetCode; - } - @Override public void setRarity(Rarity rarity) { this.rarity = rarity; diff --git a/Mage/src/main/java/mage/game/permanent/PermanentToken.java b/Mage/src/main/java/mage/game/permanent/PermanentToken.java index b1f0ea19b5..87c809fce2 100644 --- a/Mage/src/main/java/mage/game/permanent/PermanentToken.java +++ b/Mage/src/main/java/mage/game/permanent/PermanentToken.java @@ -11,6 +11,7 @@ import mage.constants.EmptyNames; import mage.game.Game; import mage.game.events.ZoneChangeEvent; import mage.game.permanent.token.Token; +import mage.util.CardUtil; import java.util.UUID; @@ -73,6 +74,11 @@ public class PermanentToken extends PermanentImpl { } } + @Override + public String toString() { + return String.format("%s - %s", getExpansionSetCode(), getName()); + } + private void copyFromToken(Token token, Game game, boolean reset) { // modify all attributes permanently (without game usage) this.name = token.getName(); @@ -105,6 +111,8 @@ public class PermanentToken extends PermanentImpl { if (this.abilities.containsClass(ChangelingAbility.class)) { this.subtype.setIsAllCreatureTypes(true); } + + CardUtil.copySetAndCardNumber(this, token); } @Override @@ -144,24 +152,4 @@ public class PermanentToken extends PermanentImpl { public MageObject getOtherFace() { return this.transformed ? token : this.token.getBackFace(); } - - @Override - public String getCardNumber() { - return token.getOriginalCardNumber(); - } - - @Override - public void setCardNumber(String cardNumber) { - throw new IllegalArgumentException("Wrong code usage: you can't change a token's card number"); - } - - @Override - public String getExpansionSetCode() { - return token.getOriginalExpansionSetCode(); - } - - @Override - public void setExpansionSetCode(String expansionSetCode) { - throw new IllegalArgumentException("Wrong code usage: you can't change a token's set code, use CardUtils.copySetAndCardNumber instead"); - } } diff --git a/Mage/src/main/java/mage/game/stack/Spell.java b/Mage/src/main/java/mage/game/stack/Spell.java index 6682a3ef3d..db684b51f7 100644 --- a/Mage/src/main/java/mage/game/stack/Spell.java +++ b/Mage/src/main/java/mage/game/stack/Spell.java @@ -202,6 +202,36 @@ public class Spell extends StackObjectImpl implements Card { return GameLog.replaceNameByColoredName(card, getSpellAbility().toString()); } + @Override + public String getExpansionSetCode() { + return card.getExpansionSetCode(); + } + + @Override + public void setExpansionSetCode(String expansionSetCode) { + throw new IllegalStateException("Wrong code usage: you can't change set code for the spell"); + } + + @Override + public String getCardNumber() { + return card.getCardNumber(); + } + + @Override + public void setCardNumber(String cardNumber) { + throw new IllegalStateException("Wrong code usage: you can't change card number for the spell"); + } + + @Override + public Integer getImageNumber() { + return card.getImageNumber(); + } + + @Override + public void setImageNumber(Integer imageNumber) { + throw new IllegalStateException("Wrong code usage: you can't change image number for the spell"); + } + @Override public boolean resolve(Game game) { boolean result; @@ -481,11 +511,6 @@ public class Spell extends StackObjectImpl implements Card { return GameLog.getColoredObjectIdName(card); } - @Override - public String getImageName() { - return card.getImageName(); - } - @Override public void setName(String name) { } @@ -704,11 +729,6 @@ public class Spell extends StackObjectImpl implements Card { return card.getRules(game); } - @Override - public String getExpansionSetCode() { - return card.getExpansionSetCode(); - } - @Override public void setFaceDown(boolean value, Game game) { faceDown = value; @@ -875,11 +895,6 @@ public class Spell extends StackObjectImpl implements Card { throw new UnsupportedOperationException("Not supported yet."); } - @Override - public String getCardNumber() { - return card.getCardNumber(); - } - @Override public boolean getUsesVariousArt() { return card.getUsesVariousArt(); diff --git a/Mage/src/main/java/mage/game/stack/StackAbility.java b/Mage/src/main/java/mage/game/stack/StackAbility.java index 0840f4105b..04c51b144e 100644 --- a/Mage/src/main/java/mage/game/stack/StackAbility.java +++ b/Mage/src/main/java/mage/game/stack/StackAbility.java @@ -52,23 +52,23 @@ public class StackAbility extends StackObjectImpl implements Ability { private boolean copy; private MageObject copyFrom; // copied card INFO (used to call original adjusters) private String name; - private String expansionSetCode; private TargetAdjuster targetAdjuster = null; private CostAdjuster costAdjuster = null; public StackAbility(Ability ability, UUID controllerId) { + super(); this.ability = ability; this.controllerId = controllerId; this.name = "stack ability (" + ability.getRule() + ')'; } public StackAbility(final StackAbility stackAbility) { + super(); this.ability = stackAbility.ability.copy(); this.controllerId = stackAbility.controllerId; this.copy = stackAbility.copy; this.copyFrom = (stackAbility.copyFrom != null ? stackAbility.copyFrom.copy() : null); this.name = stackAbility.name; - this.expansionSetCode = stackAbility.expansionSetCode; this.targetAdjuster = stackAbility.targetAdjuster; this.targetChanged = stackAbility.targetChanged; this.costAdjuster = stackAbility.costAdjuster; @@ -128,6 +128,36 @@ public class StackAbility extends StackObjectImpl implements Ability { return this.copyFrom; } + @Override + public String getExpansionSetCode() { + return ""; + } + + @Override + public void setExpansionSetCode(String expansionSetCode) { + throw new IllegalStateException("Wrong code usage: you can't change set code for the stack ability"); + } + + @Override + public String getCardNumber() { + return ""; + } + + @Override + public void setCardNumber(String cardNumber) { + throw new IllegalStateException("Wrong code usage: you can't change card number for the stack ability"); + } + + @Override + public Integer getImageNumber() { + return 0; + } + + @Override + public void setImageNumber(Integer imageNumber) { + throw new IllegalStateException("Wrong code usage: you can't change image number for the stack ability"); + } + @Override public String getName() { return name; @@ -144,12 +174,8 @@ public class StackAbility extends StackObjectImpl implements Ability { } @Override - public String getImageName() { - return name; - } - - public String getExpansionSetCode() { - return expansionSetCode; + public void setName(String name) { + this.name = name; } @Override @@ -384,15 +410,6 @@ public class StackAbility extends StackObjectImpl implements Ability { return new StackAbility(this); } - @Override - public void setName(String name) { - this.name = name; - } - - public void setExpansionSetCode(String expansionSetCode) { - this.expansionSetCode = expansionSetCode; - } - @Override public boolean checkIfClause(Game game) { return true; diff --git a/Mage/src/main/java/mage/util/CardUtil.java b/Mage/src/main/java/mage/util/CardUtil.java index 27907202f2..6caa83feac 100644 --- a/Mage/src/main/java/mage/util/CardUtil.java +++ b/Mage/src/main/java/mage/util/CardUtil.java @@ -1786,61 +1786,40 @@ public final class CardUtil { /** - * Copy image related data from one object to another (card number, set code, token type) + * Copy image related data from one object to another (set code, card number, image number) * Use it in copy/transform effects */ public static void copySetAndCardNumber(MageObject targetObject, MageObject copyFromObject) { String needSetCode; String needCardNumber; - int needTokenType; - if (copyFromObject instanceof CommandObject) { - needSetCode = ((CommandObject) copyFromObject).getExpansionSetCodeForImage(); - needCardNumber = "0"; - needTokenType = 0; - } else if (copyFromObject instanceof PermanentCard) { - needSetCode = ((PermanentCard) copyFromObject).getExpansionSetCode(); - needCardNumber = ((PermanentCard) copyFromObject).getCardNumber(); - needTokenType = 0; - } else if (copyFromObject instanceof PermanentToken) { - needSetCode = ((PermanentToken) copyFromObject).getToken().getOriginalExpansionSetCode(); - needCardNumber = ((PermanentToken) copyFromObject).getToken().getOriginalCardNumber(); - needTokenType = ((PermanentToken) copyFromObject).getToken().getTokenType(); - } else if (copyFromObject instanceof Card) { - needSetCode = ((Card) copyFromObject).getExpansionSetCode(); - needCardNumber = ((Card) copyFromObject).getCardNumber(); - needTokenType = 0; - } else if (copyFromObject instanceof Token) { - needSetCode = ((Token) copyFromObject).getOriginalExpansionSetCode(); - needCardNumber = ((Token) copyFromObject).getOriginalCardNumber(); - needTokenType = ((Token) copyFromObject).getTokenType(); - } else { - throw new IllegalStateException("Unsupported copyFromObject class: " + copyFromObject.getClass().getSimpleName()); - } + int needImageNumber; + needSetCode = copyFromObject.getExpansionSetCode(); + needCardNumber = copyFromObject.getCardNumber(); + needImageNumber = copyFromObject.getImageNumber(); if (targetObject instanceof Permanent) { - copySetAndCardNumber((Permanent) targetObject, needSetCode, needCardNumber, needTokenType); + copySetAndCardNumber((Permanent) targetObject, needSetCode, needCardNumber, needImageNumber); } else if (targetObject instanceof Token) { - copySetAndCardNumber((Token) targetObject, needSetCode, needCardNumber, needTokenType); + copySetAndCardNumber((Token) targetObject, needSetCode, needCardNumber, needImageNumber); } else { throw new IllegalStateException("Unsupported target object class: " + targetObject.getClass().getSimpleName()); } } - private static void copySetAndCardNumber(Permanent targetPermanent, String newSetCode, String newCardNumber, Integer newTokenType) { - if (targetPermanent instanceof PermanentToken) { - copySetAndCardNumber(((PermanentToken) targetPermanent).getToken(), newSetCode, newCardNumber, newTokenType); - } else if (targetPermanent instanceof PermanentCard) { + private static void copySetAndCardNumber(Permanent targetPermanent, String newSetCode, String newCardNumber, Integer newImageNumber) { + if (targetPermanent instanceof PermanentCard + || targetPermanent instanceof PermanentToken) { targetPermanent.setExpansionSetCode(newSetCode); targetPermanent.setCardNumber(newCardNumber); + targetPermanent.setImageNumber(newImageNumber); } else { throw new IllegalArgumentException("Wrong code usage: un-supported target permanent type: " + targetPermanent.getClass().getSimpleName()); } } - private static void copySetAndCardNumber(Token targetToken, String newSetCode, String newCardNumber, Integer newTokenType) { - targetToken.setOriginalExpansionSetCode(newSetCode); - targetToken.setExpansionSetCodeForImage(newSetCode); - targetToken.setOriginalCardNumber(newCardNumber); - targetToken.setTokenType(newTokenType); + private static void copySetAndCardNumber(Token targetToken, String newSetCode, String newCardNumber, Integer newImageNumber) { + targetToken.setExpansionSetCode(newSetCode); + targetToken.setCardNumber(newCardNumber); + targetToken.setImageNumber(newImageNumber); } } diff --git a/Mage/src/main/resources/tokens-database.txt b/Mage/src/main/resources/tokens-database.txt index 84143a9461..a5089bddc8 100644 --- a/Mage/src/main/resources/tokens-database.txt +++ b/Mage/src/main/resources/tokens-database.txt @@ -2,7 +2,8 @@ # Contains all possible emblems, planes, dungeons and tokens # All objects must have an image (private tokens don't have image, -# so can be ignored) +# so can be ignored, use TokenCreature instead) +# One class for same images (if you have 2/2 and */* then must use different classes) # Use verify test to check it: test_checkMissingTokenData