From 9ba0da00ff97c99dfbb551adaac52d9af382525f Mon Sep 17 00:00:00 2001 From: Artemis Kearney Date: Sun, 6 Aug 2023 20:06:32 -0500 Subject: [PATCH] Basic groundwork for extra decks (contraptions, attractions) (#10378) * extra deck cards not counted in deck size * extra deck handling in deckbuilder * move responsibility for extraDeckCard boolean to CardImpl * remove redundant field copy --- .../src/main/java/mage/client/cards/DragCardGrid.java | 10 +++++++++- .../main/java/mage/client/dialog/AddLandDialog.java | 2 +- Mage.Common/src/main/java/mage/utils/DeckBuilder.java | 6 +++--- Mage.Common/src/main/java/mage/view/CardView.java | 7 +++++++ .../src/mage/deck/AbstractCommander.java | 8 ++++---- .../src/mage/deck/AusHighlander.java | 4 ++-- .../Mage.Deck.Constructed/src/mage/deck/Brawl.java | 8 ++++---- .../src/mage/deck/CanadianHighlander.java | 4 ++-- .../src/mage/deck/EuropeanHighlander.java | 4 ++-- .../Mage.Deck.Constructed/src/mage/deck/Freeform.java | 4 ++-- .../Mage.Deck.Constructed/src/mage/deck/Momir.java | 4 ++-- .../src/mage/deck/Oathbreaker.java | 4 ++-- .../src/mage/deck/TinyLeaders.java | 4 ++-- .../Mage.Deck.Limited/src/mage/deck/Limited.java | 4 ++-- .../src/main/java/mage/player/ai/ComputerPlayer.java | 8 ++++---- .../java/org/mage/test/serverside/PlayGameTest.java | 8 ++++---- .../serverside/base/impl/CardTestPlayerAPIImpl.java | 4 ++-- .../src/test/java/org/mage/test/utils/RandomTest.java | 2 +- .../src/test/java/mage/verify/VerifyCardDataTest.java | 2 ++ Mage/src/main/java/mage/cards/Card.java | 7 +++++++ Mage/src/main/java/mage/cards/CardImpl.java | 7 +++++++ Mage/src/main/java/mage/cards/decks/Constructed.java | 4 ++-- Mage/src/main/java/mage/cards/decks/Deck.java | 7 +++++++ Mage/src/main/java/mage/cards/mock/MockCard.java | 2 ++ Mage/src/main/java/mage/cards/mock/MockSplitCard.java | 3 ++- Mage/src/main/java/mage/cards/repository/CardInfo.java | 8 ++++++++ Mage/src/main/java/mage/game/match/MatchPlayer.java | 2 +- .../java/mage/game/tournament/TournamentPlayer.java | 4 ++-- Mage/src/main/java/mage/players/PlayerImpl.java | 3 ++- 29 files changed, 97 insertions(+), 47 deletions(-) diff --git a/Mage.Client/src/main/java/mage/client/cards/DragCardGrid.java b/Mage.Client/src/main/java/mage/client/cards/DragCardGrid.java index 24ddc461366..44d6877c09c 100644 --- a/Mage.Client/src/main/java/mage/client/cards/DragCardGrid.java +++ b/Mage.Client/src/main/java/mage/client/cards/DragCardGrid.java @@ -1920,7 +1920,15 @@ public class DragCardGrid extends JPanel implements DragCardSource, DragCardTarg } private void updateCounts() { - deckNameAndCountLabel.setText(role.getName() + " - " + allCards.size()); + int extraDeckCount = allCards.stream() + .filter(c -> c.isExtraDeckCard()) + .collect(Collectors.toSet()) + .size(); + int maindeckCount = allCards.size() - extraDeckCount; + deckNameAndCountLabel.setText(role.getName() + " - " + maindeckCount + ( + extraDeckCount > 0 ? " (" + extraDeckCount + ")" + : "" + )); creatureCountLabel.setText(String.valueOf(creatureCounter.get())); landCountLabel.setText(String.valueOf(landCounter.get())); for (CardType cardType : selectByTypeButtons.keySet()) { diff --git a/Mage.Client/src/main/java/mage/client/dialog/AddLandDialog.java b/Mage.Client/src/main/java/mage/client/dialog/AddLandDialog.java index 217ffec97b2..ca47f570d56 100644 --- a/Mage.Client/src/main/java/mage/client/dialog/AddLandDialog.java +++ b/Mage.Client/src/main/java/mage/client/dialog/AddLandDialog.java @@ -473,7 +473,7 @@ public class AddLandDialog extends MageDialog { private void autoAddLands() { int deckSize = ((Number) spnDeckSize.getValue()).intValue(); - int[] lands = DeckBuildUtils.landCountSuggestion(deckSize, deck.getCards()); + int[] lands = DeckBuildUtils.landCountSuggestion(deckSize, deck.getMaindeckCards()); spnPlains.setValue(lands[0]); spnIsland.setValue(lands[1]); spnSwamp.setValue(lands[2]); diff --git a/Mage.Common/src/main/java/mage/utils/DeckBuilder.java b/Mage.Common/src/main/java/mage/utils/DeckBuilder.java index 8e18829c227..e5ed3cd15ce 100644 --- a/Mage.Common/src/main/java/mage/utils/DeckBuilder.java +++ b/Mage.Common/src/main/java/mage/utils/DeckBuilder.java @@ -77,8 +77,8 @@ public final class DeckBuilder { addCardsToDeck(remainingCards, min, max, deckCount[index]); min = max + 1; } - addCardsToDeck(remainingCards, 0, 4, deckSpells - deck.getCards().size()); - addCardsToDeck(remainingCards, 5, 10, deckSpells - deck.getCards().size()); + addCardsToDeck(remainingCards, 0, 4, deckSpells - deck.getMaindeckCards().size()); + addCardsToDeck(remainingCards, 5, 10, deckSpells - deck.getMaindeckCards().size()); addLandsToDeck(allowedColors, setsToUse, landCardPool, callback); Deck returnedDeck = deck; @@ -174,7 +174,7 @@ public final class DeckBuilder { } // Add optimal basic lands to deck. - while (deck.getCards().size() < deckSize) { + while (deck.getMaindeckCards().size() < deckSize) { ColoredManaSymbol bestColor = null; //Default to a color in the allowed colors if (allowedColors != null && !allowedColors.isEmpty()) { diff --git a/Mage.Common/src/main/java/mage/view/CardView.java b/Mage.Common/src/main/java/mage/view/CardView.java index fc542800f8c..34db51e5225 100644 --- a/Mage.Common/src/main/java/mage/view/CardView.java +++ b/Mage.Common/src/main/java/mage/view/CardView.java @@ -88,6 +88,7 @@ public class CardView extends SimpleCardView { protected CardView ability; protected int imageNumber; + protected boolean extraDeckCard; protected boolean transformable; // can toggle one card side to another (transformable cards, modal double faces) protected CardView secondCardFace; protected boolean transformed; @@ -198,6 +199,7 @@ public class CardView extends SimpleCardView { this.isToken = cardView.isToken; this.ability = cardView.ability; // reference, not copy + this.extraDeckCard = cardView.extraDeckCard; this.transformable = cardView.transformable; this.secondCardFace = cardView.secondCardFace == null ? null : new CardView(cardView.secondCardFace); this.transformed = cardView.transformed; @@ -500,6 +502,8 @@ public class CardView extends SimpleCardView { this.isToken = false; } + this.extraDeckCard = card.isExtraDeckCard(); + // transformable, double faces cards this.transformable = card.isTransformable(); @@ -1246,6 +1250,9 @@ public class CardView extends SimpleCardView { return typeText.toString(); } + public boolean isExtraDeckCard() { + return this.extraDeckCard; + } public boolean isLand() { return cardTypes.contains(CardType.LAND); } diff --git a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/AbstractCommander.java b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/AbstractCommander.java index 5eeada82573..3a1e276ed61 100644 --- a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/AbstractCommander.java +++ b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/AbstractCommander.java @@ -186,11 +186,11 @@ public abstract class AbstractCommander extends Constructed { valid = false; } - if (companion != null && deck.getCards().size() + deck.getSideboard().size() != 101) { - addError(DeckValidatorErrorType.DECK_SIZE, "Deck", "Must contain " + 101 + " cards (companion doesn't count for deck size): has " + (deck.getCards().size() + deck.getSideboard().size()) + " cards"); + if (companion != null && deck.getMaindeckCards().size() + deck.getSideboard().size() != 101) { + addError(DeckValidatorErrorType.DECK_SIZE, "Deck", "Must contain " + 101 + " cards (companion doesn't count for deck size): has " + (deck.getMaindeckCards().size() + deck.getSideboard().size()) + " cards"); valid = false; - } else if (companion == null && deck.getCards().size() + deck.getSideboard().size() != 100) { - addError(DeckValidatorErrorType.DECK_SIZE, "Deck", "Must contain " + 100 + " cards: has " + (deck.getCards().size() + deck.getSideboard().size()) + " cards"); + } else if (companion == null && deck.getMaindeckCards().size() + deck.getSideboard().size() != 100) { + addError(DeckValidatorErrorType.DECK_SIZE, "Deck", "Must contain " + 100 + " cards: has " + (deck.getMaindeckCards().size() + deck.getSideboard().size()) + " cards"); valid = false; } diff --git a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/AusHighlander.java b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/AusHighlander.java index 0eaa2ef5022..d7b3655085c 100644 --- a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/AusHighlander.java +++ b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/AusHighlander.java @@ -103,8 +103,8 @@ public class AusHighlander extends Constructed { boolean valid = true; errorsList.clear(); - if (deck.getCards().size() != getDeckMinSize()) { - addError(DeckValidatorErrorType.DECK_SIZE, "Deck", "Must contain " + getDeckMinSize() + " singleton cards: has " + (deck.getCards().size()) + " cards"); + if (deck.getMaindeckCards().size() != getDeckMinSize()) { + addError(DeckValidatorErrorType.DECK_SIZE, "Deck", "Must contain " + getDeckMinSize() + " singleton cards: has " + (deck.getMaindeckCards().size()) + " cards"); valid = false; } if (deck.getSideboard().size() > 15) { diff --git a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Brawl.java b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Brawl.java index a1242a595e6..e093d9058a6 100644 --- a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Brawl.java +++ b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Brawl.java @@ -89,11 +89,11 @@ public class Brawl extends Constructed { } } - if (companion != null && deck.getCards().size() + deck.getSideboard().size() != getDeckMinSize() + 1) { - addError(DeckValidatorErrorType.DECK_SIZE, "Deck", "Must contain " + (getDeckMinSize() + 1) + " cards (companion doesn't count in deck size requirement): has " + (deck.getCards().size() + deck.getSideboard().size()) + " cards"); + if (companion != null && deck.getMaindeckCards().size() + deck.getSideboard().size() != getDeckMinSize() + 1) { + addError(DeckValidatorErrorType.DECK_SIZE, "Deck", "Must contain " + (getDeckMinSize() + 1) + " cards (companion doesn't count in deck size requirement): has " + (deck.getMaindeckCards().size() + deck.getSideboard().size()) + " cards"); valid = false; - } else if (companion == null && deck.getCards().size() + deck.getSideboard().size() != getDeckMinSize()) { - addError(DeckValidatorErrorType.DECK_SIZE, "Deck", "Must contain " + getDeckMinSize() + " cards: has " + (deck.getCards().size() + deck.getSideboard().size()) + " cards"); + } else if (companion == null && deck.getMaindeckCards().size() + deck.getSideboard().size() != getDeckMinSize()) { + addError(DeckValidatorErrorType.DECK_SIZE, "Deck", "Must contain " + getDeckMinSize() + " cards: has " + (deck.getMaindeckCards().size() + deck.getSideboard().size()) + " cards"); valid = false; } diff --git a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/CanadianHighlander.java b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/CanadianHighlander.java index 3368b15751e..e1456c8f9d4 100644 --- a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/CanadianHighlander.java +++ b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/CanadianHighlander.java @@ -73,8 +73,8 @@ public class CanadianHighlander extends Constructed { boolean valid = true; errorsList.clear(); - if (deck.getCards().size() < 100) { - addError(DeckValidatorErrorType.DECK_SIZE, "Deck", "Must contain 100 or more singleton cards: has " + (deck.getCards().size()) + " cards"); + if (deck.getMaindeckCards().size() < 100) { + addError(DeckValidatorErrorType.DECK_SIZE, "Deck", "Must contain 100 or more singleton cards: has " + (deck.getMaindeckCards().size()) + " cards"); valid = false; } diff --git a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/EuropeanHighlander.java b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/EuropeanHighlander.java index b661dd64125..2f027231c4c 100644 --- a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/EuropeanHighlander.java +++ b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/EuropeanHighlander.java @@ -78,8 +78,8 @@ public class EuropeanHighlander extends Constructed { // Parent class checks the banned list boolean valid = super.validate(deck); - if (deck.getCards().size() < 100) { - addError(DeckValidatorErrorType.DECK_SIZE, "Deck", "Must contain 100 or more singleton cards: has " + (deck.getCards().size()) + " cards"); + if (deck.getMaindeckCards().size() < 100) { + addError(DeckValidatorErrorType.DECK_SIZE, "Deck", "Must contain 100 or more singleton cards: has " + (deck.getMaindeckCards().size()) + " cards"); valid = false; } diff --git a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Freeform.java b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Freeform.java index db1e72f91cb..cf0de94d47c 100644 --- a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Freeform.java +++ b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Freeform.java @@ -32,8 +32,8 @@ public class Freeform extends DeckValidator { boolean valid = true; errorsList.clear(); // http://magic.wizards.com/en/gameinfo/gameplay/formats/freeform - if (deck.getCards().size() < getDeckMinSize()) { - addError(DeckValidatorErrorType.DECK_SIZE, "Deck", "Must contain at least " + getDeckMinSize() + " cards: has only " + deck.getCards().size() + " cards"); + if (deck.getMaindeckCards().size() < getDeckMinSize()) { + addError(DeckValidatorErrorType.DECK_SIZE, "Deck", "Must contain at least " + getDeckMinSize() + " cards: has only " + deck.getMaindeckCards().size() + " cards"); valid = false; } return valid; diff --git a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Momir.java b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Momir.java index 67dea63fd33..cf21c5daf8f 100644 --- a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Momir.java +++ b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Momir.java @@ -33,8 +33,8 @@ public class Momir extends DeckValidator { boolean valid = true; errorsList.clear(); - if (deck.getCards().size() != getDeckMinSize()) { - addError(DeckValidatorErrorType.DECK_SIZE, "Deck", "Must contain " + getDeckMinSize() + " cards: has " + deck.getCards().size() + " cards"); + if (deck.getMaindeckCards().size() != getDeckMinSize()) { + addError(DeckValidatorErrorType.DECK_SIZE, "Deck", "Must contain " + getDeckMinSize() + " cards: has " + deck.getMaindeckCards().size() + " cards"); valid = false; } diff --git a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Oathbreaker.java b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Oathbreaker.java index 31cbee16419..e441f1e0448 100644 --- a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Oathbreaker.java +++ b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Oathbreaker.java @@ -84,8 +84,8 @@ public class Oathbreaker extends Constructed { boolean valid = true; errorsList.clear(); - if (deck.getCards().size() + deck.getSideboard().size() != 60) { - addError(DeckValidatorErrorType.DECK_SIZE, "Deck", "Must contain " + 60 + " cards: has " + (deck.getCards().size() + deck.getSideboard().size()) + " cards"); + if (deck.getMaindeckCards().size() + deck.getSideboard().size() != 60) { + addError(DeckValidatorErrorType.DECK_SIZE, "Deck", "Must contain " + 60 + " cards: has " + (deck.getMaindeckCards().size() + deck.getSideboard().size()) + " cards"); valid = false; } diff --git a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/TinyLeaders.java b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/TinyLeaders.java index ac898ab4db7..aaaa45006e8 100644 --- a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/TinyLeaders.java +++ b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/TinyLeaders.java @@ -105,8 +105,8 @@ public class TinyLeaders extends Constructed { boolean valid = true; errorsList.clear(); - if (deck.getCards().size() != getDeckMinSize()) { - addError(DeckValidatorErrorType.DECK_SIZE, "Deck", "Must contain " + getDeckMinSize() + " cards: has " + deck.getCards().size() + " cards"); + if (deck.getMaindeckCards().size() != getDeckMinSize()) { + addError(DeckValidatorErrorType.DECK_SIZE, "Deck", "Must contain " + getDeckMinSize() + " cards: has " + deck.getMaindeckCards().size() + " cards"); valid = false; } diff --git a/Mage.Server.Plugins/Mage.Deck.Limited/src/mage/deck/Limited.java b/Mage.Server.Plugins/Mage.Deck.Limited/src/mage/deck/Limited.java index 6980ddd4022..b73a9a49bac 100644 --- a/Mage.Server.Plugins/Mage.Deck.Limited/src/mage/deck/Limited.java +++ b/Mage.Server.Plugins/Mage.Deck.Limited/src/mage/deck/Limited.java @@ -31,8 +31,8 @@ public class Limited extends DeckValidator { boolean valid = true; errorsList.clear(); //20091005 - 100.2b - if (deck.getCards().size() < getDeckMinSize()) { - addError(DeckValidatorErrorType.DECK_SIZE, "Deck", "Must contain at least " + getDeckMinSize() + " cards: has only " + deck.getCards().size() + " cards"); + if (deck.getMaindeckCards().size() < getDeckMinSize()) { + addError(DeckValidatorErrorType.DECK_SIZE, "Deck", "Must contain at least " + getDeckMinSize() + " cards: has only " + deck.getMaindeckCards().size() + " cards"); valid = false; } Map counts = new HashMap<>(); 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 6f8c45db13e..0960f21e7dc 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 @@ -2257,7 +2257,7 @@ public class ComputerPlayer extends PlayerImpl implements Player { List sortedCards = new ArrayList<>(cardPool); if (!sortedCards.isEmpty()) { - while (deck.getCards().size() < DECK_SIZE) { + while (deck.getMaindeckCards().size() < DECK_SIZE) { deck.getCards().add(sortedCards.get(RandomUtil.nextInt(sortedCards.size()))); } return deck; @@ -2287,7 +2287,7 @@ public class ComputerPlayer extends PlayerImpl implements Player { // get top cards int cardNum = 0; - while (deck.getCards().size() < DECK_CARDS_COUNT && sortedCards.size() > cardNum) { + while (deck.getMaindeckCards().size() < DECK_CARDS_COUNT && sortedCards.size() > cardNum) { Card card = sortedCards.get(cardNum); if (!card.isBasic()) { deck.getCards().add(card); @@ -2349,7 +2349,7 @@ public class ComputerPlayer extends PlayerImpl implements Player { } // adds remaining lands (most popular name) - addBasicLands(deck, mostLandName, DECK_SIZE - deck.getCards().size()); + addBasicLands(deck, mostLandName, DECK_SIZE - deck.getMaindeckCards().size()); return deck; } @@ -2359,7 +2359,7 @@ public class ComputerPlayer extends PlayerImpl implements Player { DeckValidator deckValidator = DeckValidatorFactory.instance.createDeckValidator(tournament.getOptions().getMatchOptions().getDeckType()); int deckMinSize = deckValidator != null ? deckValidator.getDeckMinSize() : 0; - if (deck != null && deck.getCards().size() < deckMinSize && !deck.getSideboard().isEmpty()) { + if (deck != null && deck.getMaindeckCards().size() < deckMinSize && !deck.getSideboard().isEmpty()) { if (chosenColors == null) { for (Card card : deck.getSideboard()) { rememberPick(card, RateCard.rateCard(card, null)); diff --git a/Mage.Tests/src/test/java/org/mage/test/serverside/PlayGameTest.java b/Mage.Tests/src/test/java/org/mage/test/serverside/PlayGameTest.java index 519e8861b5c..6de49ad7d48 100644 --- a/Mage.Tests/src/test/java/org/mage/test/serverside/PlayGameTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/serverside/PlayGameTest.java @@ -43,8 +43,8 @@ public class PlayGameTest extends MageTestBase { // Deck deck = Deck.load(Sets.loadDeck("RB Aggro.dck")); Deck deck = generateRandomDeck(); - if (deck.getCards().size() < DECK_SIZE) { - throw new IllegalArgumentException("Couldn't load deck, deck size = " + deck.getCards().size() + ", but must be " + DECK_SIZE); + if (deck.getMaindeckCards().size() < DECK_SIZE) { + throw new IllegalArgumentException("Couldn't load deck, deck size = " + deck.getMaindeckCards().size() + ", but must be " + DECK_SIZE); } game.addPlayer(computerA, deck); game.loadCards(deck.getCards(), computerA.getId()); @@ -53,8 +53,8 @@ public class PlayGameTest extends MageTestBase { // Player playerB = createPlayer("ComputerB", "Computer - mad"); // Deck deck2 = Deck.load(Sets.loadDeck("RB Aggro.dck")); Deck deck2 = generateRandomDeck(); - if (deck2.getCards().size() < DECK_SIZE) { - throw new IllegalArgumentException("Couldn't load deck, deck size = " + deck2.getCards().size() + ", but must be " + DECK_SIZE); + if (deck2.getMaindeckCards().size() < DECK_SIZE) { + throw new IllegalArgumentException("Couldn't load deck, deck size = " + deck2.getMaindeckCards().size() + ", but must be " + DECK_SIZE); } game.addPlayer(computerB, deck2); game.loadCards(deck2.getCards(), computerB.getId()); diff --git a/Mage.Tests/src/test/java/org/mage/test/serverside/base/impl/CardTestPlayerAPIImpl.java b/Mage.Tests/src/test/java/org/mage/test/serverside/base/impl/CardTestPlayerAPIImpl.java index 96efb132a6c..7600ac60137 100644 --- a/Mage.Tests/src/test/java/org/mage/test/serverside/base/impl/CardTestPlayerAPIImpl.java +++ b/Mage.Tests/src/test/java/org/mage/test/serverside/base/impl/CardTestPlayerAPIImpl.java @@ -219,8 +219,8 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement } Deck deck = Deck.load(list, false, false, loadedCardInfo); logger.debug("Done!"); - if (deck.getCards().size() < 40) { - throw new IllegalArgumentException("Couldn't load deck, deck size=" + deck.getCards().size()); + if (deck.getMaindeckCards().size() < 40) { + throw new IllegalArgumentException("Couldn't load deck, deck size=" + deck.getMaindeckCards().size()); } game.loadCards(deck.getCards(), player.getId()); diff --git a/Mage.Tests/src/test/java/org/mage/test/utils/RandomTest.java b/Mage.Tests/src/test/java/org/mage/test/utils/RandomTest.java index 9face45d4e4..2de26778ff4 100644 --- a/Mage.Tests/src/test/java/org/mage/test/utils/RandomTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/utils/RandomTest.java @@ -144,7 +144,7 @@ public class RandomTest { Player player = new HumanPlayer("random", RangeOfInfluence.ALL, 1); Game game = new TwoPlayerDuel(MultiplayerAttackOption.MULTIPLE, RangeOfInfluence.ALL, MulliganType.GAME_DEFAULT.getMulligan(0), 50); Deck deck = DeckTestUtils.buildRandomDeck("WGUBR", false, "GRN"); - player.getLibrary().addAll(deck.getCards(), game); + player.getLibrary().addAll(deck.getMaindeckCards(), game); // multiple cards analyze for (int i = 0; i < player.getLibrary().size(); i++) { diff --git a/Mage.Verify/src/test/java/mage/verify/VerifyCardDataTest.java b/Mage.Verify/src/test/java/mage/verify/VerifyCardDataTest.java index 461f47b2377..45b359078c1 100644 --- a/Mage.Verify/src/test/java/mage/verify/VerifyCardDataTest.java +++ b/Mage.Verify/src/test/java/mage/verify/VerifyCardDataTest.java @@ -584,6 +584,8 @@ public class VerifyCardDataTest { } if ((deckCards.getCards().size() + deckCards.getSideboard().size()) < 10) { + // note: does not check whether cards are extra deck cards (contraptions/attractions); + // may succeed for decks with such cards when it should fail errorsList.add("Error: sample deck contains too little cards (" + deckCards.getSideboard().size() + ") " + deckName); totalErrorFiles++; continue; diff --git a/Mage/src/main/java/mage/cards/Card.java b/Mage/src/main/java/mage/cards/Card.java index 1cd68e065a4..d96ef8357ef 100644 --- a/Mage/src/main/java/mage/cards/Card.java +++ b/Mage/src/main/java/mage/cards/Card.java @@ -80,6 +80,13 @@ public interface Card extends MageObject { return null; } + /** + * Is this an extra deck card? (such as contraptions and attractions) + * @return true if this is an extra deck card, false otherwise + */ + default boolean isExtraDeckCard() { + return false; + } void assignNewId(); void addInfo(String key, String value, Game game); diff --git a/Mage/src/main/java/mage/cards/CardImpl.java b/Mage/src/main/java/mage/cards/CardImpl.java index a84d73f7495..8a86ea1f7e8 100644 --- a/Mage/src/main/java/mage/cards/CardImpl.java +++ b/Mage/src/main/java/mage/cards/CardImpl.java @@ -53,6 +53,7 @@ public abstract class CardImpl extends MageObjectImpl implements Card { protected boolean usesVariousArt = false; protected boolean morphCard; protected List attachments = new ArrayList<>(); + protected boolean extraDeckCard = false; protected CardImpl(UUID ownerId, CardSetInfo setInfo, CardType[] cardTypes, String costs) { this(ownerId, setInfo, cardTypes, costs, SpellAbilityType.BASE); @@ -130,6 +131,7 @@ public abstract class CardImpl extends MageObjectImpl implements Card { flipCardName = card.flipCardName; usesVariousArt = card.usesVariousArt; morphCard = card.morphCard; + extraDeckCard = card.extraDeckCard; this.attachments.addAll(card.attachments); } @@ -952,4 +954,9 @@ public abstract class CardImpl extends MageObjectImpl implements Card { // Only way to get here is if none of the effects on the card care about mana color. return false; } + + @Override + public boolean isExtraDeckCard() { + return extraDeckCard; + } } diff --git a/Mage/src/main/java/mage/cards/decks/Constructed.java b/Mage/src/main/java/mage/cards/decks/Constructed.java index 1b98f3c46bb..588eb807f8c 100644 --- a/Mage/src/main/java/mage/cards/decks/Constructed.java +++ b/Mage/src/main/java/mage/cards/decks/Constructed.java @@ -214,8 +214,8 @@ public class Constructed extends DeckValidator { boolean valid = true; errorsList.clear(); //20091005 - 100.2a - if (deck.getCards().size() < getDeckMinSize()) { - addError(DeckValidatorErrorType.DECK_SIZE, "Deck", "Must contain at least " + getDeckMinSize() + " cards: has only " + deck.getCards().size() + " cards"); + if (deck.getMaindeckCards().size() < getDeckMinSize()) { + addError(DeckValidatorErrorType.DECK_SIZE, "Deck", "Must contain at least " + getDeckMinSize() + " cards: has only " + deck.getMaindeckCards().size() + " cards"); valid = false; } //20130713 - 100.4a diff --git a/Mage/src/main/java/mage/cards/decks/Deck.java b/Mage/src/main/java/mage/cards/decks/Deck.java index eb851cbb4b2..a5ff5fb02f4 100644 --- a/Mage/src/main/java/mage/cards/decks/Deck.java +++ b/Mage/src/main/java/mage/cards/decks/Deck.java @@ -227,6 +227,13 @@ public class Deck implements Serializable, Copyable { return cards; } + public Set getMaindeckCards() { + return cards + .stream() + .filter(card -> !card.isExtraDeckCard()) + .collect(Collectors.toSet()); + } + public Card findCard(UUID cardId) { return cards .stream() diff --git a/Mage/src/main/java/mage/cards/mock/MockCard.java b/Mage/src/main/java/mage/cards/mock/MockCard.java index 65f67db84a0..7361b6cc04e 100644 --- a/Mage/src/main/java/mage/cards/mock/MockCard.java +++ b/Mage/src/main/java/mage/cards/mock/MockCard.java @@ -88,6 +88,8 @@ public class MockCard extends CardImpl { for (String ruleText : card.getRules()) { this.addAbility(textAbilityFromString(ruleText)); } + + this.extraDeckCard = card.isExtraDeckCard(); } protected MockCard(final MockCard card) { diff --git a/Mage/src/main/java/mage/cards/mock/MockSplitCard.java b/Mage/src/main/java/mage/cards/mock/MockSplitCard.java index 60c9f4d399c..605667b7b8e 100644 --- a/Mage/src/main/java/mage/cards/mock/MockSplitCard.java +++ b/Mage/src/main/java/mage/cards/mock/MockSplitCard.java @@ -19,7 +19,6 @@ import java.util.List; * @author North */ public class MockSplitCard extends SplitCard { - public MockSplitCard(CardInfo card) { super(null, new CardSetInfo(card.getName(), card.getSetCode(), card.getCardNumber(), card.getRarity()), card.getTypes().toArray(new CardType[0]), @@ -62,6 +61,8 @@ public class MockSplitCard extends SplitCard { this.rightHalfCard = new MockSplitCardHalf(rightHalf); ((SplitCardHalf) this.rightHalfCard).setParentCard(this); } + + this.extraDeckCard = card.isExtraDeckCard(); } protected MockSplitCard(final MockSplitCard card) { diff --git a/Mage/src/main/java/mage/cards/repository/CardInfo.java b/Mage/src/main/java/mage/cards/repository/CardInfo.java index 21cdefba646..e838b1cf252 100644 --- a/Mage/src/main/java/mage/cards/repository/CardInfo.java +++ b/Mage/src/main/java/mage/cards/repository/CardInfo.java @@ -113,6 +113,8 @@ public class CardInfo { protected String modalDoubleFacedSecondSideName; @DatabaseField protected String meldsToCardName; + @DatabaseField + protected boolean isExtraDeckCard; // if you add new field with card side name then update CardRepository.addNewNames too @@ -232,6 +234,8 @@ public class CardInfo { // Starting loyalty this.startingLoyalty = CardUtil.convertLoyaltyOrDefense(card.getStartingLoyalty()); this.startingDefense = CardUtil.convertLoyaltyOrDefense(card.getStartingDefense()); + + this.isExtraDeckCard = card.isExtraDeckCard(); } public Card getCard() { @@ -482,4 +486,8 @@ public class CardInfo { public String toString() { return String.format("%s (%s, %s)", getName(), getSetCode(), getCardNumber()); } + + public boolean isExtraDeckCard() { + return isExtraDeckCard; + } } diff --git a/Mage/src/main/java/mage/game/match/MatchPlayer.java b/Mage/src/main/java/mage/game/match/MatchPlayer.java index be7fdb77e5e..e8a833517be 100644 --- a/Mage/src/main/java/mage/game/match/MatchPlayer.java +++ b/Mage/src/main/java/mage/game/match/MatchPlayer.java @@ -95,7 +95,7 @@ public class MatchPlayer implements Serializable { public Deck generateDeck(DeckValidator deckValidator) { // auto complete deck - while (deck.getCards().size() < deckValidator.getDeckMinSize() && !deck.getSideboard().isEmpty()) { + while (deck.getMaindeckCards().size() < deckValidator.getDeckMinSize() && !deck.getSideboard().isEmpty()) { Card card = deck.getSideboard().iterator().next(); deck.getCards().add(card); deck.getSideboard().remove(card); diff --git a/Mage/src/main/java/mage/game/tournament/TournamentPlayer.java b/Mage/src/main/java/mage/game/tournament/TournamentPlayer.java index 1cbae00f00d..c44c218f02e 100644 --- a/Mage/src/main/java/mage/game/tournament/TournamentPlayer.java +++ b/Mage/src/main/java/mage/game/tournament/TournamentPlayer.java @@ -105,8 +105,8 @@ public class TournamentPlayer { If user fails to submit deck on time, submit deck as is if meets minimum size, else add basic lands per suggested land counts */ - if (deck.getCards().size() < minDeckSize) { - int[] lands = DeckBuildUtils.landCountSuggestion(minDeckSize, deck.getCards()); + if (deck.getMaindeckCards().size() < minDeckSize) { + int[] lands = DeckBuildUtils.landCountSuggestion(minDeckSize, deck.getMaindeckCards()); Set landSets = TournamentUtil.getLandSetCodeForDeckSets(deck.getExpansionSetCodes()); deck.getCards().addAll(TournamentUtil.getLands("Plains", lands[0], landSets)); deck.getCards().addAll(TournamentUtil.getLands("Island", lands[1], landSets)); diff --git a/Mage/src/main/java/mage/players/PlayerImpl.java b/Mage/src/main/java/mage/players/PlayerImpl.java index 1dc56cc0338..08fc43e6240 100644 --- a/Mage/src/main/java/mage/players/PlayerImpl.java +++ b/Mage/src/main/java/mage/players/PlayerImpl.java @@ -388,11 +388,12 @@ public abstract class PlayerImpl implements Player, Serializable { @Override public void useDeck(Deck deck, Game game) { library.clear(); - library.addAll(deck.getCards(), game); + library.addAll(deck.getMaindeckCards(), game); sideboard.clear(); for (Card card : deck.getSideboard()) { sideboard.add(card); } + //TODO ARTI initialize extra decks here! } /**