GUI: added problem cards selection on legality label clicks (#6854)

This commit is contained in:
Oleg Agafonov 2020-08-17 05:14:12 +04:00
parent a4af5501f9
commit 486c0d7c2c
17 changed files with 167 additions and 105 deletions

View file

@ -1064,6 +1064,19 @@ public class DragCardGrid extends JPanel implements DragCardSource, DragCardTarg
} }
} }
public void selectByName(List<String> cardNames) {
for (List<List<CardView>> gridRow : cardGrid) {
for (List<CardView> stack : gridRow) {
for (CardView card : stack) {
if (cardNames.contains(card.getName())) {
card.setSelected(true);
cardViews.get(card.getId()).update(card);
}
}
}
}
}
private void hideSelection() { private void hideSelection() {
Collection<CardView> toHide = dragCardList(); Collection<CardView> toHide = dragCardList();
for (DragCardGridListener l : listeners) { for (DragCardGridListener l : listeners) {

View file

@ -113,7 +113,7 @@ public class LegalityLabel extends JLabel {
return sortedErrorsList.stream() return sortedErrorsList.stream()
.reduce("<html><body>" .reduce("<html><body>"
+ "<p>Deck is <span style='color:#BF544A;font-weight:bold;'>INVALID</span></p>" + "<p>Deck is <span style='color:#BF544A;font-weight:bold;'>INVALID</span></p>"
+ "<u>The following problems have been found:</u>" + "<u>The following problems have been found (click to select problem cards):</u>"
+ "<br>" + "<br>"
+ "<table style=\"table-layout: fixed; width: " + TOOLTIP_TABLE_WIDTH + "px\">", + "<table style=\"table-layout: fixed; width: " + TOOLTIP_TABLE_WIDTH + "px\">",
(str, error) -> String.format("%s<tr><td style=\"word-wrap: break-word\"><b>%s</b></td><td style=\"word-wrap: break-word\">%s</td></tr>", str, escapeHtml(error.getGroup()), escapeHtml(error.getMessage())), String::concat) (str, error) -> String.format("%s<tr><td style=\"word-wrap: break-word\"><b>%s</b></td><td style=\"word-wrap: break-word\">%s</td></tr>", str, escapeHtml(error.getGroup()), escapeHtml(error.getMessage())), String::concat)
@ -125,7 +125,7 @@ public class LegalityLabel extends JLabel {
return sortedErrorsList.stream() return sortedErrorsList.stream()
.reduce("<html><body>" .reduce("<html><body>"
+ "<p>Deck is <span style='color:#b8860b;font-weight:bold;'>PARTLY VALID</span></p>" + "<p>Deck is <span style='color:#b8860b;font-weight:bold;'>PARTLY VALID</span></p>"
+ "<u>The following problems have been found:</u>" + "<u>The following problems have been found (click to select problem cards):</u>"
+ "<br>" + "<br>"
+ "<table style=\"table-layout: fixed; width: " + TOOLTIP_TABLE_WIDTH + "px\">", + "<table style=\"table-layout: fixed; width: " + TOOLTIP_TABLE_WIDTH + "px\">",
(str, error) -> String.format("%s<tr><td style=\"word-wrap: break-word\"><b>%s</b></td><td style=\"word-wrap: break-word\">%s</td></tr>", str, escapeHtml(error.getGroup()), escapeHtml(error.getMessage())), String::concat) (str, error) -> String.format("%s<tr><td style=\"word-wrap: break-word\"><b>%s</b></td><td style=\"word-wrap: break-word\">%s</td></tr>", str, escapeHtml(error.getGroup()), escapeHtml(error.getMessage())), String::concat)

View file

@ -9,6 +9,7 @@ import mage.client.MageFrame;
import mage.client.SessionHandler; import mage.client.SessionHandler;
import mage.client.cards.BigCard; import mage.client.cards.BigCard;
import mage.client.cards.ICardGrid; import mage.client.cards.ICardGrid;
import mage.client.components.LegalityLabel;
import mage.client.constants.Constants.DeckEditorMode; import mage.client.constants.Constants.DeckEditorMode;
import mage.client.deck.generator.DeckGenerator; import mage.client.deck.generator.DeckGenerator;
import mage.client.deck.generator.DeckGenerator.DeckGeneratorException; import mage.client.deck.generator.DeckGenerator.DeckGeneratorException;
@ -27,12 +28,11 @@ import mage.view.SimpleCardView;
import org.apache.log4j.Logger; import org.apache.log4j.Logger;
import javax.swing.*; import javax.swing.*;
import javax.swing.border.Border;
import javax.swing.filechooser.FileFilter; import javax.swing.filechooser.FileFilter;
import java.awt.*; import java.awt.*;
import java.awt.dnd.DropTarget; import java.awt.dnd.DropTarget;
import java.awt.event.ActionEvent; import java.awt.event.*;
import java.awt.event.ActionListener;
import java.awt.event.HierarchyEvent;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.util.List; import java.util.List;
@ -48,11 +48,15 @@ import static mage.cards.decks.DeckFormats.XMAGE_INFO;
public class DeckEditorPanel extends javax.swing.JPanel { public class DeckEditorPanel extends javax.swing.JPanel {
private static final Logger logger = Logger.getLogger(DeckEditorPanel.class); private static final Logger logger = Logger.getLogger(DeckEditorPanel.class);
private static final Border LEGALITY_LABEL_BORDER_SELECTED = BorderFactory.createLineBorder(Color.gray, 2);
private static final Border LEGALITY_LABEL_BORDER_EMPTY = BorderFactory.createEmptyBorder();
private final JFileChooser fcSelectDeck; private final JFileChooser fcSelectDeck;
private final JFileChooser fcImportDeck; private final JFileChooser fcImportDeck;
private final JFileChooser fcExportDeck; private final JFileChooser fcExportDeck;
private Deck deck = new Deck();
private final Map<UUID, Card> temporaryCards = new HashMap<>(); // Cards dragged out of one part of the view into another private final Map<UUID, Card> temporaryCards = new HashMap<>(); // Cards dragged out of one part of the view into another
private final String LAST_DECK_FOLDER = "lastDeckFolder";
private Deck deck = new Deck();
private boolean isShowCardInfo = false; private boolean isShowCardInfo = false;
private UUID tableId; private UUID tableId;
private DeckEditorMode mode; private DeckEditorMode mode;
@ -60,7 +64,41 @@ public class DeckEditorPanel extends javax.swing.JPanel {
private javax.swing.Timer countdown; private javax.swing.Timer countdown;
private UpdateDeckTask updateDeckTask; private UpdateDeckTask updateDeckTask;
private int timeToSubmit = -1; private int timeToSubmit = -1;
private final String LAST_DECK_FOLDER = "lastDeckFolder"; // Variables declaration - do not modify//GEN-BEGIN:variables
private mage.client.cards.BigCard bigCard;
private javax.swing.JButton btnAddLand;
private javax.swing.JButton btnExit;
private javax.swing.JButton btnExport;
private javax.swing.JButton btnGenDeck;
private javax.swing.JButton btnImport;
private javax.swing.JButton btnLegality;
private javax.swing.JButton btnLoad;
private javax.swing.JButton btnNew;
private javax.swing.JButton btnSave;
private javax.swing.JButton btnSubmit;
private javax.swing.JButton btnSubmitTimer;
private JComponent cardInfoPane;
/*
private org.mage.plugins.card.info.CardInfoPaneImpl cardInfoPane;
*/
private mage.client.deckeditor.CardSelector cardSelector;
private mage.client.deckeditor.DeckArea deckArea;
private mage.client.deckeditor.DeckLegalityPanel deckLegalityDisplay;
private javax.swing.JLabel lblDeckName;
private javax.swing.JPanel panelDeck;
private javax.swing.JPanel panelDeckCreate;
private javax.swing.JPanel panelDeckDraft;
private javax.swing.JPanel panelDeckExit;
private javax.swing.JPanel panelDeckLands;
private javax.swing.JPanel panelDeckLoad;
private javax.swing.JPanel panelDeckName;
private javax.swing.JPanel panelDeckSave;
private javax.swing.JPanel panelInfo;
private javax.swing.JPanel panelLeft;
private javax.swing.JSplitPane panelRight;
private javax.swing.JScrollPane scrollPaneInfo;
private javax.swing.JTextField txtDeckName;
private javax.swing.JTextField txtTimeRemaining;
public DeckEditorPanel() { public DeckEditorPanel() {
initComponents(); initComponents();
@ -105,6 +143,38 @@ public class DeckEditorPanel extends javax.swing.JPanel {
} }
} }
}); });
// deck legality cards selection
Arrays.stream(deckLegalityDisplay.getComponents())
.filter(c -> c instanceof LegalityLabel)
.forEach(c -> {
c.addMouseListener(new MouseAdapter() {
public void mouseClicked(MouseEvent e) {
List<String> cardNames = new ArrayList<>();
LegalityLabel label = (LegalityLabel) e.getComponent();
label.getValidator().getErrorsList().stream()
.map(DeckValidatorError::getCardName)
.filter(Objects::nonNull)
.forEach(cardNames::add);
deckArea.getDeckList().deselectAll();
deckArea.getDeckList().selectByName(cardNames);
deckArea.getSideboardList().deselectAll();
deckArea.getSideboardList().selectByName(cardNames);
}
@Override
public void mouseEntered(MouseEvent e) {
LegalityLabel label = (LegalityLabel) e.getComponent();
label.setBorder(LEGALITY_LABEL_BORDER_SELECTED);
}
@Override
public void mouseExited(MouseEvent e) {
LegalityLabel label = (LegalityLabel) e.getComponent();
label.setBorder(LEGALITY_LABEL_BORDER_EMPTY);
}
});
});
} }
/** /**
@ -1447,43 +1517,6 @@ public class DeckEditorPanel extends javax.swing.JPanel {
this.deckLegalityDisplay.setVisible(true); this.deckLegalityDisplay.setVisible(true);
this.deckLegalityDisplay.validateDeck(deck); this.deckLegalityDisplay.validateDeck(deck);
}//GEN-LAST:event_btnLegalityActionPerformed }//GEN-LAST:event_btnLegalityActionPerformed
// Variables declaration - do not modify//GEN-BEGIN:variables
private mage.client.cards.BigCard bigCard;
private javax.swing.JButton btnAddLand;
private javax.swing.JButton btnExit;
private javax.swing.JButton btnExport;
private javax.swing.JButton btnGenDeck;
private javax.swing.JButton btnImport;
private javax.swing.JButton btnLegality;
private javax.swing.JButton btnLoad;
private javax.swing.JButton btnNew;
private javax.swing.JButton btnSave;
private javax.swing.JButton btnSubmit;
private javax.swing.JButton btnSubmitTimer;
private JComponent cardInfoPane;
/*
private org.mage.plugins.card.info.CardInfoPaneImpl cardInfoPane;
*/
private mage.client.deckeditor.CardSelector cardSelector;
private mage.client.deckeditor.DeckArea deckArea;
private mage.client.deckeditor.DeckLegalityPanel deckLegalityDisplay;
private javax.swing.JLabel lblDeckName;
private javax.swing.JPanel panelDeck;
private javax.swing.JPanel panelDeckCreate;
private javax.swing.JPanel panelDeckDraft;
private javax.swing.JPanel panelDeckExit;
private javax.swing.JPanel panelDeckLands;
private javax.swing.JPanel panelDeckLoad;
private javax.swing.JPanel panelDeckName;
private javax.swing.JPanel panelDeckSave;
private javax.swing.JPanel panelInfo;
private javax.swing.JPanel panelLeft;
private javax.swing.JSplitPane panelRight;
private javax.swing.JScrollPane scrollPaneInfo;
private javax.swing.JTextField txtDeckName;
private javax.swing.JTextField txtTimeRemaining;
// End of variables declaration//GEN-END:variables // End of variables declaration//GEN-END:variables
} }

View file

@ -103,7 +103,6 @@ public class DeckLegalityPanel extends javax.swing.JPanel {
protected LegalityLabel addLegalityLabel(DeckValidator validator) { protected LegalityLabel addLegalityLabel(DeckValidator validator) {
LegalityLabel label = new LegalityLabel(validator); LegalityLabel label = new LegalityLabel(validator);
add(label); add(label);
return label; return label;
} }

View file

@ -140,7 +140,7 @@ public class AusHighlander extends Constructed {
String cn = entry.getKey(); String cn = entry.getKey();
if (pointMap.containsKey(cn)) { if (pointMap.containsKey(cn)) {
totalPoints += pointMap.get(cn); totalPoints += pointMap.get(cn);
addError(DeckValidatorErrorType.OTHER, entry.getKey(), " " + pointMap.get(cn) + " point " + cn); addError(DeckValidatorErrorType.OTHER, entry.getKey(), " " + pointMap.get(cn) + " point " + cn, true);
} }
} }
if (totalPoints > 7) { if (totalPoints > 7) {

View file

@ -73,12 +73,12 @@ public class Brawl extends Constructed {
if (brawler != null) { if (brawler != null) {
ManaUtil.collectColorIdentity(colorIdentity, brawler.getColorIdentity()); ManaUtil.collectColorIdentity(colorIdentity, brawler.getColorIdentity());
if (bannedCommander.contains(brawler.getName())) { if (bannedCommander.contains(brawler.getName())) {
addError(DeckValidatorErrorType.PRIMARY, "Brawl", "Brawler banned (" + brawler.getName() + ')'); addError(DeckValidatorErrorType.PRIMARY, brawler.getName(), "Brawler banned (" + brawler.getName() + ')', true);
valid = false; valid = false;
} }
if (!((brawler.isCreature() && brawler.isLegendary()) if (!((brawler.isCreature() && brawler.isLegendary())
|| brawler.isPlaneswalker() || brawler.getAbilities().contains(CanBeYourCommanderAbility.getInstance()))) { || brawler.isPlaneswalker() || brawler.getAbilities().contains(CanBeYourCommanderAbility.getInstance()))) {
addError(DeckValidatorErrorType.PRIMARY, "Brawl", "Invalid Brawler (" + brawler.getName() + ')'); addError(DeckValidatorErrorType.PRIMARY, brawler.getName(), "Brawler Invalid (" + brawler.getName() + ')', true);
valid = false; valid = false;
} }
} }
@ -98,7 +98,7 @@ public class Brawl extends Constructed {
for (String bannedCard : banned) { for (String bannedCard : banned) {
if (counts.containsKey(bannedCard)) { if (counts.containsKey(bannedCard)) {
addError(DeckValidatorErrorType.BANNED, "Banned", bannedCard); addError(DeckValidatorErrorType.BANNED, bannedCard, "Banned", true);
valid = false; valid = false;
} }
} }
@ -116,7 +116,7 @@ public class Brawl extends Constructed {
&& !(colorIdentity.isColorless() && !(colorIdentity.isColorless()
&& basicsInDeck.size() == 1 && basicsInDeck.size() == 1
&& basicsInDeck.contains(card.getName()))) { && basicsInDeck.contains(card.getName()))) {
addError(DeckValidatorErrorType.OTHER, card.getName(), "Invalid color (" + colorIdentity.toString() + ')'); addError(DeckValidatorErrorType.OTHER, card.getName(), "Invalid color (" + colorIdentity.toString() + ')', true);
valid = false; valid = false;
} }
} }
@ -125,14 +125,14 @@ public class Brawl extends Constructed {
&& !(colorIdentity.isColorless() && !(colorIdentity.isColorless()
&& basicsInDeck.size() == 1 && basicsInDeck.size() == 1
&& basicsInDeck.contains(card.getName()))) { && basicsInDeck.contains(card.getName()))) {
addError(DeckValidatorErrorType.OTHER, card.getName(), "Invalid color (" + colorIdentity.toString() + ')'); addError(DeckValidatorErrorType.OTHER, card.getName(), "Invalid color (" + colorIdentity.toString() + ')', true);
valid = false; valid = false;
} }
} }
for (Card card : deck.getCards()) { for (Card card : deck.getCards()) {
if (!isSetAllowed(card.getExpansionSetCode())) { if (!isSetAllowed(card.getExpansionSetCode())) {
if (!legalSets(card)) { if (!legalSets(card)) {
addError(DeckValidatorErrorType.WRONG_SET, card.getName(), "Not allowed Set: " + card.getExpansionSetCode()); addError(DeckValidatorErrorType.WRONG_SET, card.getName(), "Not allowed Set: " + card.getExpansionSetCode(), true);
valid = false; valid = false;
} }
} }
@ -140,7 +140,7 @@ public class Brawl extends Constructed {
for (Card card : deck.getSideboard()) { for (Card card : deck.getSideboard()) {
if (!isSetAllowed(card.getExpansionSetCode())) { if (!isSetAllowed(card.getExpansionSetCode())) {
if (!legalSets(card)) { if (!legalSets(card)) {
addError(DeckValidatorErrorType.WRONG_SET, card.getName(), "Not allowed Set: " + card.getExpansionSetCode()); addError(DeckValidatorErrorType.WRONG_SET, card.getName(), "Not allowed Set: " + card.getExpansionSetCode(), true);
valid = false; valid = false;
} }
} }
@ -153,7 +153,7 @@ public class Brawl extends Constructed {
if (ability instanceof CompanionAbility) { if (ability instanceof CompanionAbility) {
CompanionAbility companionAbility = (CompanionAbility) ability; CompanionAbility companionAbility = (CompanionAbility) ability;
if (!companionAbility.isLegal(cards, getDeckMinSize())) { if (!companionAbility.isLegal(cards, getDeckMinSize())) {
addError(DeckValidatorErrorType.PRIMARY, companion.getName(), "Deck invalid for companion"); addError(DeckValidatorErrorType.PRIMARY, companion.getName(), "Brawl Companion Invalid", true);
valid = false; valid = false;
} }
break; break;

View file

@ -98,7 +98,7 @@ public class CanadianHighlander extends Constructed {
String cn = entry.getKey(); String cn = entry.getKey();
if (pointMap.containsKey(cn)) { if (pointMap.containsKey(cn)) {
totalPoints += pointMap.get(cn); totalPoints += pointMap.get(cn);
addError(DeckValidatorErrorType.OTHER, entry.getKey(), " " + pointMap.get(cn) + " point " + cn); addError(DeckValidatorErrorType.OTHER, entry.getKey(), " " + pointMap.get(cn) + " point " + cn, true);
} }
} }
if (totalPoints > allowedPoints) { if (totalPoints > allowedPoints) {

View file

@ -160,7 +160,7 @@ public class Commander extends Constructed {
for (String bannedCard : banned) { for (String bannedCard : banned) {
if (counts.containsKey(bannedCard)) { if (counts.containsKey(bannedCard)) {
addError(DeckValidatorErrorType.BANNED, "Banned", bannedCard); addError(DeckValidatorErrorType.BANNED, bannedCard, "Banned", true);
valid = false; valid = false;
} }
} }
@ -171,18 +171,18 @@ public class Commander extends Constructed {
} }
for (Card commander : commanders) { for (Card commander : commanders) {
if (bannedCommander.contains(commander.getName())) { if (bannedCommander.contains(commander.getName())) {
addError(DeckValidatorErrorType.PRIMARY, "Commander", "Commander banned (" + commander.getName() + ')'); addError(DeckValidatorErrorType.PRIMARY, commander.getName(), "Commander banned (" + commander.getName() + ')', true);
valid = false; valid = false;
} }
if ((!commander.isCreature() || !commander.isLegendary()) if ((!commander.isCreature() || !commander.isLegendary())
&& (!commander.isPlaneswalker() || !commander.getAbilities().contains(CanBeYourCommanderAbility.getInstance()))) { && (!commander.isPlaneswalker() || !commander.getAbilities().contains(CanBeYourCommanderAbility.getInstance()))) {
addError(DeckValidatorErrorType.PRIMARY, "Commander", "Commander invalid (" + commander.getName() + ')'); addError(DeckValidatorErrorType.PRIMARY, commander.getName(), "Commander invalid (" + commander.getName() + ')', true);
valid = false; valid = false;
} }
if (commanders.size() == 2) { if (commanders.size() == 2) {
if (commander.getAbilities().contains(PartnerAbility.getInstance())) { if (commander.getAbilities().contains(PartnerAbility.getInstance())) {
if (bannedPartner.contains(commander.getName())) { if (bannedPartner.contains(commander.getName())) {
addError(DeckValidatorErrorType.PRIMARY, "Commander", "Partner banned (" + commander.getName() + ')'); addError(DeckValidatorErrorType.PRIMARY, commander.getName(), "Commander Partner banned (" + commander.getName() + ')', true);
valid = false; valid = false;
} }
} else { } else {
@ -193,7 +193,7 @@ public class Commander extends Constructed {
.map(PartnerWithAbility::getPartnerName) .map(PartnerWithAbility::getPartnerName)
.anyMatch(commanderNames::contains); .anyMatch(commanderNames::contains);
if (!partnersWith) { if (!partnersWith) {
addError(DeckValidatorErrorType.PRIMARY, "Commander", "Commander without Partner (" + commander.getName() + ')'); addError(DeckValidatorErrorType.PRIMARY, commander.getName(), "Commander without Partner (" + commander.getName() + ')', true);
valid = false; valid = false;
} }
} }
@ -208,20 +208,20 @@ public class Commander extends Constructed {
for (Card card : deck.getCards()) { for (Card card : deck.getCards()) {
if (!ManaUtil.isColorIdentityCompatible(colorIdentity, card.getColorIdentity())) { if (!ManaUtil.isColorIdentityCompatible(colorIdentity, card.getColorIdentity())) {
addError(DeckValidatorErrorType.OTHER, card.getName(), "Invalid color (" + colorIdentity.toString() + ')'); addError(DeckValidatorErrorType.OTHER, card.getName(), "Invalid color (" + colorIdentity.toString() + ')', true);
valid = false; valid = false;
} }
} }
for (Card card : deck.getSideboard()) { for (Card card : deck.getSideboard()) {
if (!ManaUtil.isColorIdentityCompatible(colorIdentity, card.getColorIdentity())) { if (!ManaUtil.isColorIdentityCompatible(colorIdentity, card.getColorIdentity())) {
addError(DeckValidatorErrorType.OTHER, card.getName(), "Invalid color (" + colorIdentity.toString() + ')'); addError(DeckValidatorErrorType.OTHER, card.getName(), "Invalid color (" + colorIdentity.toString() + ')', true);
valid = false; valid = false;
} }
} }
for (Card card : deck.getCards()) { for (Card card : deck.getCards()) {
if (!isSetAllowed(card.getExpansionSetCode())) { if (!isSetAllowed(card.getExpansionSetCode())) {
if (!legalSets(card)) { if (!legalSets(card)) {
addError(DeckValidatorErrorType.WRONG_SET, card.getName(), "Not allowed Set: " + card.getExpansionSetCode()); addError(DeckValidatorErrorType.WRONG_SET, card.getName(), "Not allowed Set: " + card.getExpansionSetCode(), true);
valid = false; valid = false;
} }
} }
@ -229,7 +229,7 @@ public class Commander extends Constructed {
for (Card card : deck.getSideboard()) { for (Card card : deck.getSideboard()) {
if (!isSetAllowed(card.getExpansionSetCode())) { if (!isSetAllowed(card.getExpansionSetCode())) {
if (!legalSets(card)) { if (!legalSets(card)) {
addError(DeckValidatorErrorType.WRONG_SET, card.getName(), "Not allowed Set: " + card.getExpansionSetCode()); addError(DeckValidatorErrorType.WRONG_SET, card.getName(), "Not allowed Set: " + card.getExpansionSetCode(), true);
valid = false; valid = false;
} }
} }
@ -242,7 +242,7 @@ public class Commander extends Constructed {
if (ability instanceof CompanionAbility) { if (ability instanceof CompanionAbility) {
CompanionAbility companionAbility = (CompanionAbility) ability; CompanionAbility companionAbility = (CompanionAbility) ability;
if (!companionAbility.isLegal(cards, getDeckMinSize())) { if (!companionAbility.isLegal(cards, getDeckMinSize())) {
addError(DeckValidatorErrorType.PRIMARY, companion.getName(), "Deck invalid for companion"); addError(DeckValidatorErrorType.PRIMARY, companion.getName(), "Commander Companion (deck invalid for companion)", true);
valid = false; valid = false;
} }
break; break;

View file

@ -120,7 +120,7 @@ public class FreeformCommander extends Constructed {
} }
for (Card commander : commanders) { for (Card commander : commanders) {
if (!commander.isCreature() || !commander.isLegendary()) { if (!commander.isCreature() || !commander.isLegendary()) {
addError(DeckValidatorErrorType.PRIMARY, "Commander", "For Freeform Commander, the commander must be a creature or be legendary. Yours was: " + commander.getName()); addError(DeckValidatorErrorType.PRIMARY, commander.getName(), "For Freeform Commander, the commander must be a creature or be legendary. Yours was: " + commander.getName(), true);
valid = false; valid = false;
} }
if (commanders.size() == 2) { if (commanders.size() == 2) {
@ -132,7 +132,7 @@ public class FreeformCommander extends Constructed {
.map(PartnerWithAbility::getPartnerName) .map(PartnerWithAbility::getPartnerName)
.anyMatch(commanderNames::contains); .anyMatch(commanderNames::contains);
if (!partnersWith) { if (!partnersWith) {
addError(DeckValidatorErrorType.PRIMARY, "Commander", "Commander without Partner (" + commander.getName() + ')'); addError(DeckValidatorErrorType.PRIMARY, commander.getName(), "Commander without Partner (" + commander.getName() + ')', true);
valid = false; valid = false;
} }
} }
@ -147,13 +147,13 @@ public class FreeformCommander extends Constructed {
for (Card card : deck.getCards()) { for (Card card : deck.getCards()) {
if (!ManaUtil.isColorIdentityCompatible(colorIdentity, card.getColorIdentity())) { if (!ManaUtil.isColorIdentityCompatible(colorIdentity, card.getColorIdentity())) {
addError(DeckValidatorErrorType.OTHER, card.getName(), "Invalid color (" + colorIdentity.toString() + ')'); addError(DeckValidatorErrorType.OTHER, card.getName(), "Invalid color (" + colorIdentity.toString() + ')', true);
valid = false; valid = false;
} }
} }
for (Card card : deck.getSideboard()) { for (Card card : deck.getSideboard()) {
if (!ManaUtil.isColorIdentityCompatible(colorIdentity, card.getColorIdentity())) { if (!ManaUtil.isColorIdentityCompatible(colorIdentity, card.getColorIdentity())) {
addError(DeckValidatorErrorType.OTHER, card.getName(), "Invalid color (" + colorIdentity.toString() + ')'); addError(DeckValidatorErrorType.OTHER, card.getName(), "Invalid color (" + colorIdentity.toString() + ')', true);
valid = false; valid = false;
} }
} }
@ -165,7 +165,7 @@ public class FreeformCommander extends Constructed {
if (ability instanceof CompanionAbility) { if (ability instanceof CompanionAbility) {
CompanionAbility companionAbility = (CompanionAbility) ability; CompanionAbility companionAbility = (CompanionAbility) ability;
if (!companionAbility.isLegal(cards, getDeckMinSize())) { if (!companionAbility.isLegal(cards, getDeckMinSize())) {
addError(DeckValidatorErrorType.PRIMARY, companion.getName(), "Deck invalid for companion"); addError(DeckValidatorErrorType.PRIMARY, companion.getName(), "Commander Companion (deck invalid for companion)", true);
valid = false; valid = false;
} }
break; break;

View file

@ -41,7 +41,7 @@ public class Momir extends DeckValidator {
List<String> basicLandNames = new ArrayList<>(Arrays.asList("Forest", "Island", "Mountain", "Swamp", "Plains", "Wastes")); List<String> basicLandNames = new ArrayList<>(Arrays.asList("Forest", "Island", "Mountain", "Swamp", "Plains", "Wastes"));
for (Card card : deck.getCards()) { for (Card card : deck.getCards()) {
if (!basicLandNames.contains(card.getName())) { if (!basicLandNames.contains(card.getName())) {
addError(DeckValidatorErrorType.OTHER, card.getName(), "Only basic lands are allowed"); addError(DeckValidatorErrorType.OTHER, card.getName(), "Only basic lands are allowed", true);
valid = false; valid = false;
} }
} }

View file

@ -96,7 +96,7 @@ public class Oathbreaker extends Vintage {
for (String bannedCard : banned) { for (String bannedCard : banned) {
if (counts.containsKey(bannedCard)) { if (counts.containsKey(bannedCard)) {
addError(DeckValidatorErrorType.BANNED, "Banned", bannedCard); addError(DeckValidatorErrorType.BANNED, bannedCard, "Banned", true);
valid = false; valid = false;
} }
} }
@ -121,7 +121,7 @@ public class Oathbreaker extends Vintage {
// color identity from commanders only, not spell // color identity from commanders only, not spell
ManaUtil.collectColorIdentity(allCommandersColor, commander.getColorIdentity()); ManaUtil.collectColorIdentity(allCommandersColor, commander.getColorIdentity());
} else { } else {
addError(DeckValidatorErrorType.PRIMARY, "Oathbreaker", "Only planeswalker can be Oathbreaker, not " + commander.getName()); addError(DeckValidatorErrorType.PRIMARY, commander.getName(), "Oathbreaker (only planeswalker can be Oathbreaker, not " + commander.getName(), true);
valid = false; valid = false;
} }
} }
@ -154,7 +154,7 @@ public class Oathbreaker extends Vintage {
} }
} }
if (!partnersWith) { if (!partnersWith) {
addError(DeckValidatorErrorType.PRIMARY, "Oathbreaker", "Oathbreaker without Partner (" + commander.getName() + ')'); addError(DeckValidatorErrorType.PRIMARY, commander.getName(), "Oathbreaker without Partner (" + commander.getName() + ')', true);
valid = false; valid = false;
} }
} }
@ -176,7 +176,7 @@ public class Oathbreaker extends Vintage {
} }
} }
if (!haveSameColor) { if (!haveSameColor) {
addError(DeckValidatorErrorType.PRIMARY, "Signature Spell", "Can't find oathbreaker with compatible color identity (" + spell.getName() + " - " + spellColor + ")"); addError(DeckValidatorErrorType.PRIMARY, spell.getName(), "Signature Spell (can't find oathbreaker with compatible color identity: " + spell.getName() + " - " + spellColor + ")", true);
valid = false; valid = false;
} }
} }
@ -190,7 +190,7 @@ public class Oathbreaker extends Vintage {
for (Card card : deck.getCards()) { for (Card card : deck.getCards()) {
if (!ManaUtil.isColorIdentityCompatible(allCommandersColor, card.getColorIdentity())) { if (!ManaUtil.isColorIdentityCompatible(allCommandersColor, card.getColorIdentity())) {
addError(DeckValidatorErrorType.OTHER, card.getName(), "Invalid color (" + card.getColorIdentity() + ')'); addError(DeckValidatorErrorType.OTHER, card.getName(), "Invalid color (" + card.getColorIdentity() + ')', true);
valid = false; valid = false;
} }
} }
@ -198,7 +198,7 @@ public class Oathbreaker extends Vintage {
for (Card card : deck.getSideboard()) { for (Card card : deck.getSideboard()) {
if (!isSetAllowed(card.getExpansionSetCode())) { if (!isSetAllowed(card.getExpansionSetCode())) {
if (!legalSets(card)) { if (!legalSets(card)) {
addError(DeckValidatorErrorType.WRONG_SET, card.getName(), "Not allowed Set: " + card.getExpansionSetCode()); addError(DeckValidatorErrorType.WRONG_SET, card.getName(), "Not allowed Set: " + card.getExpansionSetCode(), true);
valid = false; valid = false;
} }
} }

View file

@ -113,7 +113,7 @@ public class PennyDreadfulCommander extends Constructed {
for (String wantedCard : counts.keySet()) { for (String wantedCard : counts.keySet()) {
if (!(pdAllowed.containsKey(wantedCard))) { if (!(pdAllowed.containsKey(wantedCard))) {
addError(DeckValidatorErrorType.BANNED, "Banned", wantedCard); addError(DeckValidatorErrorType.BANNED, wantedCard, "Banned", true);
valid = false; valid = false;
} }
} }
@ -124,12 +124,12 @@ public class PennyDreadfulCommander extends Constructed {
} }
for (Card commander : commanders) { for (Card commander : commanders) {
if (bannedCommander.contains(commander.getName())) { if (bannedCommander.contains(commander.getName())) {
addError(DeckValidatorErrorType.PRIMARY, "Commander", "Commander banned (" + commander.getName() + ')'); addError(DeckValidatorErrorType.PRIMARY, commander.getName(), "Commander banned (" + commander.getName() + ')', true);
valid = false; valid = false;
} }
if ((!commander.isCreature() || !commander.isLegendary()) if ((!commander.isCreature() || !commander.isLegendary())
&& (!commander.isPlaneswalker() || !commander.getAbilities().contains(CanBeYourCommanderAbility.getInstance()))) { && (!commander.isPlaneswalker() || !commander.getAbilities().contains(CanBeYourCommanderAbility.getInstance()))) {
addError(DeckValidatorErrorType.PRIMARY, "Commander", "Commander invalid (" + commander.getName() + ')'); addError(DeckValidatorErrorType.PRIMARY, commander.getName(), "Commander invalid (" + commander.getName() + ')', true);
valid = false; valid = false;
} }
if (commanders.size() == 2) { if (commanders.size() == 2) {
@ -141,7 +141,7 @@ public class PennyDreadfulCommander extends Constructed {
.map(PartnerWithAbility::getPartnerName) .map(PartnerWithAbility::getPartnerName)
.anyMatch(commanderNames::contains); .anyMatch(commanderNames::contains);
if (!partnersWith) { if (!partnersWith) {
addError(DeckValidatorErrorType.PRIMARY, "Commander", "Commander without Partner (" + commander.getName() + ')'); addError(DeckValidatorErrorType.PRIMARY, commander.getName(), "Commander without Partner (" + commander.getName() + ')', true);
valid = false; valid = false;
} }
} }
@ -156,20 +156,20 @@ public class PennyDreadfulCommander extends Constructed {
for (Card card : deck.getCards()) { for (Card card : deck.getCards()) {
if (!ManaUtil.isColorIdentityCompatible(colorIdentity, card.getColorIdentity())) { if (!ManaUtil.isColorIdentityCompatible(colorIdentity, card.getColorIdentity())) {
addError(DeckValidatorErrorType.OTHER, card.getName(), "Invalid color (" + colorIdentity.toString() + ')'); addError(DeckValidatorErrorType.OTHER, card.getName(), "Invalid color (" + colorIdentity.toString() + ')', true);
valid = false; valid = false;
} }
} }
for (Card card : deck.getSideboard()) { for (Card card : deck.getSideboard()) {
if (!ManaUtil.isColorIdentityCompatible(colorIdentity, card.getColorIdentity())) { if (!ManaUtil.isColorIdentityCompatible(colorIdentity, card.getColorIdentity())) {
addError(DeckValidatorErrorType.OTHER, card.getName(), "Invalid color (" + colorIdentity.toString() + ')'); addError(DeckValidatorErrorType.OTHER, card.getName(), "Invalid color (" + colorIdentity.toString() + ')', true);
valid = false; valid = false;
} }
} }
for (Card card : deck.getCards()) { for (Card card : deck.getCards()) {
if (!isSetAllowed(card.getExpansionSetCode())) { if (!isSetAllowed(card.getExpansionSetCode())) {
if (!legalSets(card)) { if (!legalSets(card)) {
addError(DeckValidatorErrorType.WRONG_SET, card.getName(), "Not allowed Set: " + card.getExpansionSetCode()); addError(DeckValidatorErrorType.WRONG_SET, card.getName(), "Not allowed Set: " + card.getExpansionSetCode(), true);
valid = false; valid = false;
} }
} }
@ -177,7 +177,7 @@ public class PennyDreadfulCommander extends Constructed {
for (Card card : deck.getSideboard()) { for (Card card : deck.getSideboard()) {
if (!isSetAllowed(card.getExpansionSetCode())) { if (!isSetAllowed(card.getExpansionSetCode())) {
if (!legalSets(card)) { if (!legalSets(card)) {
addError(DeckValidatorErrorType.WRONG_SET, card.getName(), "Not allowed Set: " + card.getExpansionSetCode()); addError(DeckValidatorErrorType.WRONG_SET, card.getName(), "Not allowed Set: " + card.getExpansionSetCode(), true);
valid = false; valid = false;
} }
} }
@ -190,7 +190,7 @@ public class PennyDreadfulCommander extends Constructed {
if (ability instanceof CompanionAbility) { if (ability instanceof CompanionAbility) {
CompanionAbility companionAbility = (CompanionAbility) ability; CompanionAbility companionAbility = (CompanionAbility) ability;
if (!companionAbility.isLegal(cards, getDeckMinSize())) { if (!companionAbility.isLegal(cards, getDeckMinSize())) {
addError(DeckValidatorErrorType.PRIMARY, companion.getName(), "Deck invalid for companion"); addError(DeckValidatorErrorType.PRIMARY, companion.getName(), "Commander Companion (deck invalid for companion)", true);
valid = false; valid = false;
} }
break; break;

View file

@ -119,7 +119,7 @@ public class TinyLeaders extends Constructed {
for (String bannedCard : banned) { for (String bannedCard : banned) {
if (counts.containsKey(bannedCard)) { if (counts.containsKey(bannedCard)) {
addError(DeckValidatorErrorType.BANNED, "Banned", bannedCard); addError(DeckValidatorErrorType.BANNED, bannedCard, "Banned", true);
valid = false; valid = false;
} }
} }
@ -163,11 +163,11 @@ public class TinyLeaders extends Constructed {
} }
} }
} else { } else {
addError(DeckValidatorErrorType.PRIMARY, "Commander", "Commander banned (" + commander.getName() + ')'); addError(DeckValidatorErrorType.PRIMARY, commander.getName(), "Commander banned (" + commander.getName() + ')', true);
valid = false; valid = false;
} }
} else { } else {
addError(DeckValidatorErrorType.PRIMARY, "Commander", "Commander invalide (" + commander.getName() + ')'); addError(DeckValidatorErrorType.PRIMARY, commander.getName(), "Commander invalide (" + commander.getName() + ')', true);
valid = false; valid = false;
} }
} else { } else {
@ -177,7 +177,7 @@ public class TinyLeaders extends Constructed {
for (Card card : deck.getCards()) { for (Card card : deck.getCards()) {
if (!isSetAllowed(card.getExpansionSetCode())) { if (!isSetAllowed(card.getExpansionSetCode())) {
if (!legalSets(card)) { if (!legalSets(card)) {
addError(DeckValidatorErrorType.WRONG_SET, card.getName(), "Not allowed Set " + card.getExpansionSetCode()); addError(DeckValidatorErrorType.WRONG_SET, card.getName(), "Not allowed Set " + card.getExpansionSetCode(), true);
valid = false; valid = false;
} }
} }
@ -185,7 +185,7 @@ public class TinyLeaders extends Constructed {
for (Card card : deck.getSideboard()) { for (Card card : deck.getSideboard()) {
if (!isSetAllowed(card.getExpansionSetCode())) { if (!isSetAllowed(card.getExpansionSetCode())) {
if (!legalSets(card)) { if (!legalSets(card)) {
addError(DeckValidatorErrorType.WRONG_SET, card.getName(), "Not allowed Set " + card.getExpansionSetCode()); addError(DeckValidatorErrorType.WRONG_SET, card.getName(), "Not allowed Set " + card.getExpansionSetCode(), true);
valid = false; valid = false;
} }
} }
@ -195,22 +195,22 @@ public class TinyLeaders extends Constructed {
private boolean isCardFormatValid(Card card, Card commander, FilterMana color) { private boolean isCardFormatValid(Card card, Card commander, FilterMana color) {
if (!cardHasValideColor(color, card)) { if (!cardHasValideColor(color, card)) {
addError(DeckValidatorErrorType.OTHER, card.getName(), "Invalid color (" + commander.getName() + ')'); addError(DeckValidatorErrorType.OTHER, card.getName(), "Invalid color (" + commander.getName() + ')', true);
return false; return false;
} }
//905.5b - Converted mana cost must be 3 or less //905.5b - Converted mana cost must be 3 or less
if (card instanceof SplitCard) { if (card instanceof SplitCard) {
if (((SplitCard) card).getLeftHalfCard().getManaCost().convertedManaCost() > 3) { if (((SplitCard) card).getLeftHalfCard().getManaCost().convertedManaCost() > 3) {
addError(DeckValidatorErrorType.OTHER, card.getName(), "Invalid cost (" + ((SplitCard) card).getLeftHalfCard().getManaCost().convertedManaCost() + ')'); addError(DeckValidatorErrorType.OTHER, card.getName(), "Invalid cost (" + ((SplitCard) card).getLeftHalfCard().getManaCost().convertedManaCost() + ')', true);
return false; return false;
} }
if (((SplitCard) card).getRightHalfCard().getManaCost().convertedManaCost() > 3) { if (((SplitCard) card).getRightHalfCard().getManaCost().convertedManaCost() > 3) {
addError(DeckValidatorErrorType.OTHER, card.getName(), "Invalid cost (" + ((SplitCard) card).getRightHalfCard().getManaCost().convertedManaCost() + ')'); addError(DeckValidatorErrorType.OTHER, card.getName(), "Invalid cost (" + ((SplitCard) card).getRightHalfCard().getManaCost().convertedManaCost() + ')', true);
return false; return false;
} }
} else if (card.getManaCost().convertedManaCost() > 3) { } else if (card.getManaCost().convertedManaCost() > 3) {
addError(DeckValidatorErrorType.OTHER, card.getName(), "Invalid cost (" + card.getManaCost().convertedManaCost() + ')'); addError(DeckValidatorErrorType.OTHER, card.getName(), "Invalid cost (" + card.getManaCost().convertedManaCost() + ')', true);
return false; return false;
} }
return true; return true;

View file

@ -39,7 +39,7 @@ public class Limited extends DeckValidator {
countCards(counts, deck.getCards()); countCards(counts, deck.getCards());
for (Map.Entry<String, Integer> entry : counts.entrySet()) { for (Map.Entry<String, Integer> entry : counts.entrySet()) {
if (entry.getValue() > 7 && entry.getKey().equals("Seven Dwarves")) { if (entry.getValue() > 7 && entry.getKey().equals("Seven Dwarves")) {
addError(DeckValidatorErrorType.OTHER, entry.getKey(), "Too many: " + entry.getValue()); addError(DeckValidatorErrorType.OTHER, entry.getKey(), "Too many: " + entry.getValue(), true);
valid = false; valid = false;
} }
} }

View file

@ -77,7 +77,7 @@ public class Constructed extends DeckValidator {
for (String bannedCard : banned) { for (String bannedCard : banned) {
if (counts.containsKey(bannedCard)) { if (counts.containsKey(bannedCard)) {
addError(DeckValidatorErrorType.BANNED, "Banned", bannedCard); addError(DeckValidatorErrorType.BANNED, bannedCard, "Banned", true);
valid = false; valid = false;
} }
} }
@ -86,7 +86,7 @@ public class Constructed extends DeckValidator {
if (counts.containsKey(restrictedCard)) { if (counts.containsKey(restrictedCard)) {
int count = counts.get(restrictedCard); int count = counts.get(restrictedCard);
if (count > 1) { if (count > 1) {
addError(DeckValidatorErrorType.OTHER, restrictedCard, "Restricted amount: " + count); addError(DeckValidatorErrorType.OTHER, restrictedCard, "Restricted amount: " + count, true);
valid = false; valid = false;
} }
} }
@ -143,7 +143,7 @@ public class Constructed extends DeckValidator {
} }
} }
if (!legal && !errorsListContainsGroup(card.getName())) { if (!legal && !errorsListContainsGroup(card.getName())) {
addError(DeckValidatorErrorType.OTHER, card.getName(), "Invalid rarity: " + card.getRarity()); addError(DeckValidatorErrorType.OTHER, card.getName(), "Invalid rarity: " + card.getRarity(), true);
} }
return legal; return legal;
} }
@ -181,7 +181,7 @@ public class Constructed extends DeckValidator {
} }
if (!legal && !errorsListContainsGroup(card.getName())) { if (!legal && !errorsListContainsGroup(card.getName())) {
addError(DeckValidatorErrorType.WRONG_SET, card.getName(), "Invalid set: " + card.getExpansionSetCode()); addError(DeckValidatorErrorType.WRONG_SET, card.getName(), "Invalid set: " + card.getExpansionSetCode(), true);
} }
return legal; return legal;
} }
@ -192,11 +192,11 @@ public class Constructed extends DeckValidator {
if (entry.getValue() > maxCopies if (entry.getValue() > maxCopies
&& !basicLandNames.contains(entry.getKey()) && !basicLandNames.contains(entry.getKey())
&& !anyNumberCardsAllowed.contains(entry.getKey())) { && !anyNumberCardsAllowed.contains(entry.getKey())) {
addError(DeckValidatorErrorType.OTHER, entry.getKey(), "Too many: " + entry.getValue()); addError(DeckValidatorErrorType.OTHER, entry.getKey(), "Too many: " + entry.getValue(), true);
valid = false; valid = false;
} }
if (entry.getValue() > 7 && entry.getKey().equals("Seven Dwarves")) { if (entry.getValue() > 7 && entry.getKey().equals("Seven Dwarves")) {
addError(DeckValidatorErrorType.OTHER, entry.getKey(), "Too many: " + entry.getValue()); addError(DeckValidatorErrorType.OTHER, entry.getKey(), "Too many: " + entry.getValue(), true);
valid = false; valid = false;
} }
} }

View file

@ -93,7 +93,7 @@ public abstract class DeckValidator implements Serializable {
int otherErrorsCount = list.size() - maxErrors; int otherErrorsCount = list.size() - maxErrors;
list = list.stream().limit(maxErrors).collect(Collectors.toList()); list = list.stream().limit(maxErrors).collect(Collectors.toList());
list.add(new DeckValidatorError(DeckValidatorErrorType.OTHER, "...", list.add(new DeckValidatorError(DeckValidatorErrorType.OTHER, "...",
"and more " + otherErrorsCount + " error" + (otherErrorsCount > 1 ? "s" : ""))); "and more " + otherErrorsCount + " error" + (otherErrorsCount > 1 ? "s" : ""), null));
} }
return list; return list;
@ -106,8 +106,19 @@ public abstract class DeckValidator implements Serializable {
.collect(Collectors.joining(", ")); .collect(Collectors.joining(", "));
} }
/**
* @param isCardError group contains card name that can be selected as wrong card
*/
public void addError(DeckValidatorErrorType errorType, String group, String message, boolean isCardError) {
addError(errorType, group, message, (isCardError ? group : null));
}
public void addError(DeckValidatorErrorType errorType, String group, String message) { public void addError(DeckValidatorErrorType errorType, String group, String message) {
this.errorsList.add(new DeckValidatorError(errorType, group, message)); addError(errorType, group, message, null);
}
private void addError(DeckValidatorErrorType errorType, String group, String message, String cardName) {
this.errorsList.add(new DeckValidatorError(errorType, group, message, cardName));
} }
public boolean errorsListContainsGroup(String group) { public boolean errorsListContainsGroup(String group) {

View file

@ -8,11 +8,13 @@ public class DeckValidatorError {
private final DeckValidatorErrorType errorType; private final DeckValidatorErrorType errorType;
private final String group; private final String group;
private final String message; private final String message;
private final String cardName;
public DeckValidatorError(DeckValidatorErrorType errorType, String group, String message) { public DeckValidatorError(DeckValidatorErrorType errorType, String group, String message, String cardName) {
this.errorType = errorType; this.errorType = errorType;
this.group = group; this.group = group;
this.message = message; this.message = message;
this.cardName = cardName;
} }
public DeckValidatorErrorType getErrorType() { public DeckValidatorErrorType getErrorType() {
@ -26,4 +28,8 @@ public class DeckValidatorError {
public String getMessage() { public String getMessage() {
return this.message; return this.message;
} }
public String getCardName() {
return this.cardName;
}
} }