mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-11 16:26:22 +00:00
Deck Importer support for Adventure, Quest, and Planar Conquest (#8681)
* Some cleanup. * Expanded/fixed basic land set functions for quest and adventure. * Get land sets from unlocked planes in conquest mode. * Add importer for Adventure, Quest, and Conquest. * Remove unused import * Remove redundant override * Deprecate hasBasicLands predicate. * Delete getManaNameAndSymbol --------- Co-authored-by: Jetz <Jetz722@gmail.com>
This commit is contained in:
@@ -1018,16 +1018,13 @@ public final class CardEdition implements Comparable<CardEdition> {
|
||||
|
||||
public static final Predicate<CardEdition> HAS_BOOSTER_BOX = edition -> edition.getBoosterBoxCount() > 0;
|
||||
|
||||
@Deprecated //Use CardEdition::hasBasicLands and a nonnull test.
|
||||
public static final Predicate<CardEdition> hasBasicLands = ed -> {
|
||||
if (ed == null) {
|
||||
// Happens for new sets with "???" code
|
||||
return false;
|
||||
}
|
||||
for(String landName : MagicColor.Constant.BASIC_LANDS) {
|
||||
if (null == StaticData.instance().getCommonCards().getCard(landName, ed.getCode(), 0))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
return ed.hasBasicLands();
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1048,7 +1045,7 @@ public final class CardEdition implements Comparable<CardEdition> {
|
||||
|
||||
public boolean hasBasicLands() {
|
||||
for(String landName : MagicColor.Constant.BASIC_LANDS) {
|
||||
if (null == StaticData.instance().getCommonCards().getCard(landName, this.getCode(), 0))
|
||||
if (this.getCardInSet(landName).isEmpty())
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
||||
@@ -49,6 +49,16 @@ public class DeckRecognizer {
|
||||
LIMITED_CARD,
|
||||
CARD_FROM_NOT_ALLOWED_SET,
|
||||
CARD_FROM_INVALID_SET,
|
||||
/**
|
||||
* Valid card request, but can't be imported because the player does not have enough copies.
|
||||
* Should be replaced with a different printing if possible.
|
||||
*/
|
||||
CARD_NOT_IN_INVENTORY,
|
||||
/**
|
||||
* Valid card request for a card that isn't in the player's inventory, but new copies can be acquired freely.
|
||||
* Usually used for basic lands. Should be supplied to the import controller by the editor.
|
||||
*/
|
||||
FREE_CARD_NOT_IN_INVENTORY,
|
||||
// Warning messages
|
||||
WARNING_MESSAGE,
|
||||
UNKNOWN_CARD,
|
||||
@@ -63,10 +73,14 @@ public class DeckRecognizer {
|
||||
CARD_TYPE,
|
||||
CARD_RARITY,
|
||||
CARD_CMC,
|
||||
MANA_COLOUR
|
||||
MANA_COLOUR;
|
||||
|
||||
public static final EnumSet<TokenType> CARD_TOKEN_TYPES = EnumSet.of(LEGAL_CARD, LIMITED_CARD, CARD_FROM_NOT_ALLOWED_SET, CARD_FROM_INVALID_SET, CARD_NOT_IN_INVENTORY, FREE_CARD_NOT_IN_INVENTORY);
|
||||
public static final EnumSet<TokenType> IN_DECK_TOKEN_TYPES = EnumSet.of(LEGAL_CARD, LIMITED_CARD, DECK_NAME, FREE_CARD_NOT_IN_INVENTORY);
|
||||
public static final EnumSet<TokenType> CARD_PLACEHOLDER_TOKEN_TYPES = EnumSet.of(CARD_TYPE, CARD_RARITY, CARD_CMC, MANA_COLOUR);
|
||||
}
|
||||
|
||||
public enum LimitedCardType{
|
||||
public enum LimitedCardType {
|
||||
BANNED,
|
||||
RESTRICTED,
|
||||
}
|
||||
@@ -108,6 +122,10 @@ public class DeckRecognizer {
|
||||
return new Token(TokenType.CARD_FROM_INVALID_SET, count, card, cardRequestHasSetCode);
|
||||
}
|
||||
|
||||
public static Token NotInInventoryFree(final PaperCard card, final int count, final DeckSection section) {
|
||||
return new Token(TokenType.FREE_CARD_NOT_IN_INVENTORY, count, card, section, true);
|
||||
}
|
||||
|
||||
// WARNING MESSAGES
|
||||
// ================
|
||||
public static Token UnknownCard(final String cardName, final String setCode, final int count) {
|
||||
@@ -126,6 +144,10 @@ public class DeckRecognizer {
|
||||
return new Token(TokenType.WARNING_MESSAGE, msg);
|
||||
}
|
||||
|
||||
public static Token NotInInventory(final PaperCard card, final int count, final DeckSection section) {
|
||||
return new Token(TokenType.CARD_NOT_IN_INVENTORY, count, card, section, false);
|
||||
}
|
||||
|
||||
/* =================================
|
||||
* DECK SECTIONS
|
||||
* ================================= */
|
||||
@@ -239,14 +261,11 @@ public class DeckRecognizer {
|
||||
/**
|
||||
* Filters all token types that have a PaperCard instance set (not null)
|
||||
* @return true for tokens of type:
|
||||
* LEGAL_CARD, LIMITED_CARD, CARD_FROM_NOT_ALLOWED_SET and CARD_FROM_INVALID_SET.
|
||||
* LEGAL_CARD, LIMITED_CARD, CARD_FROM_NOT_ALLOWED_SET and CARD_FROM_INVALID_SET, CARD_NOT_IN_INVENTORY, FREE_CARD_NOT_IN_INVENTORY.
|
||||
* False otherwise.
|
||||
*/
|
||||
public boolean isCardToken() {
|
||||
return (this.type == TokenType.LEGAL_CARD ||
|
||||
this.type == TokenType.LIMITED_CARD ||
|
||||
this.type == TokenType.CARD_FROM_NOT_ALLOWED_SET ||
|
||||
this.type == TokenType.CARD_FROM_INVALID_SET);
|
||||
return TokenType.CARD_TOKEN_TYPES.contains(this.type);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -255,9 +274,7 @@ public class DeckRecognizer {
|
||||
* LEGAL_CARD, LIMITED_CARD, DECK_NAME; false otherwise.
|
||||
*/
|
||||
public boolean isTokenForDeck() {
|
||||
return (this.type == TokenType.LEGAL_CARD ||
|
||||
this.type == TokenType.LIMITED_CARD ||
|
||||
this.type == TokenType.DECK_NAME);
|
||||
return TokenType.IN_DECK_TOKEN_TYPES.contains(this.type);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -266,7 +283,7 @@ public class DeckRecognizer {
|
||||
* False otherwise.
|
||||
*/
|
||||
public boolean isCardTokenForDeck() {
|
||||
return (this.type == TokenType.LEGAL_CARD || this.type == TokenType.LIMITED_CARD);
|
||||
return isCardToken() && isTokenForDeck();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -276,10 +293,7 @@ public class DeckRecognizer {
|
||||
* CARD_RARITY, CARD_CMC, CARD_TYPE, MANA_COLOUR
|
||||
*/
|
||||
public boolean isCardPlaceholder(){
|
||||
return (this.type == TokenType.CARD_RARITY ||
|
||||
this.type == TokenType.CARD_CMC ||
|
||||
this.type == TokenType.MANA_COLOUR ||
|
||||
this.type == TokenType.CARD_TYPE);
|
||||
return TokenType.CARD_PLACEHOLDER_TOKEN_TYPES.contains(this.type);
|
||||
}
|
||||
|
||||
/** Determines if current token is a Deck Section token
|
||||
@@ -536,7 +550,7 @@ public class DeckRecognizer {
|
||||
PaperCard tokenCard = token.getCard();
|
||||
|
||||
if (isAllowed(tokenSection)) {
|
||||
if (!tokenSection.equals(referenceDeckSectionInParsing)) {
|
||||
if (tokenSection != referenceDeckSectionInParsing) {
|
||||
Token sectionToken = Token.DeckSection(tokenSection.name(), this.allowedDeckSections);
|
||||
// just check that last token is stack is a card placeholder.
|
||||
// In that case, add the new section token before the placeholder
|
||||
@@ -575,7 +589,7 @@ public class DeckRecognizer {
|
||||
refLine = purgeAllLinks(refLine);
|
||||
|
||||
String line;
|
||||
if (StringUtils.startsWith(refLine, LINE_COMMENT_DELIMITER_OR_MD_HEADER))
|
||||
if (refLine.startsWith(LINE_COMMENT_DELIMITER_OR_MD_HEADER))
|
||||
line = refLine.replaceAll(LINE_COMMENT_DELIMITER_OR_MD_HEADER, "");
|
||||
else
|
||||
line = refLine.trim(); // Remove any trailing formatting
|
||||
@@ -584,7 +598,7 @@ public class DeckRecognizer {
|
||||
// Final fantasy cards like Summon: Choco/Mog should be ommited to be recognized. TODO: fix maybe for future cards
|
||||
if (!line.contains("Summon:"))
|
||||
line = SEARCH_SINGLE_SLASH.matcher(line).replaceFirst(" // ");
|
||||
if (StringUtils.startsWith(line, ASTERISK)) // markdown lists (tappedout md export)
|
||||
if (line.startsWith(ASTERISK)) // Markdown lists (tappedout md export)
|
||||
line = line.substring(2);
|
||||
|
||||
// == Patches to Corner Cases
|
||||
@@ -600,8 +614,8 @@ public class DeckRecognizer {
|
||||
Token result = recogniseCardToken(line, referenceSection);
|
||||
if (result == null)
|
||||
result = recogniseNonCardToken(line);
|
||||
return result != null ? result : StringUtils.startsWith(refLine, DOUBLE_SLASH) ||
|
||||
StringUtils.startsWith(refLine, LINE_COMMENT_DELIMITER_OR_MD_HEADER) ?
|
||||
return result != null ? result : refLine.startsWith(DOUBLE_SLASH) ||
|
||||
refLine.startsWith(LINE_COMMENT_DELIMITER_OR_MD_HEADER) ?
|
||||
new Token(TokenType.COMMENT, 0, refLine) : new Token(TokenType.UNKNOWN_TEXT, 0, refLine);
|
||||
}
|
||||
|
||||
@@ -613,7 +627,7 @@ public class DeckRecognizer {
|
||||
while (m.find()) {
|
||||
line = line.replaceAll(m.group(), "").trim();
|
||||
}
|
||||
if (StringUtils.endsWith(line, "()"))
|
||||
if (line.endsWith("()"))
|
||||
return line.substring(0, line.length()-2);
|
||||
return line;
|
||||
}
|
||||
@@ -741,21 +755,12 @@ public class DeckRecognizer {
|
||||
// This would save tons of time in parsing Input + would also allow to return UnsupportedCardTokens beforehand
|
||||
private DeckSection getTokenSection(String deckSec, DeckSection currentDeckSection, PaperCard card){
|
||||
if (deckSec != null) {
|
||||
DeckSection cardSection;
|
||||
switch (deckSec.toUpperCase().trim()) {
|
||||
case "MB":
|
||||
cardSection = DeckSection.Main;
|
||||
break;
|
||||
case "SB":
|
||||
cardSection = DeckSection.Sideboard;
|
||||
break;
|
||||
case "CM":
|
||||
cardSection = DeckSection.Commander;
|
||||
break;
|
||||
default:
|
||||
cardSection = DeckSection.matchingSection(card);
|
||||
break;
|
||||
}
|
||||
DeckSection cardSection = switch (deckSec.toUpperCase().trim()) {
|
||||
case "MB" -> DeckSection.Main;
|
||||
case "SB" -> DeckSection.Sideboard;
|
||||
case "CM" -> DeckSection.Commander;
|
||||
default -> DeckSection.matchingSection(card);
|
||||
};
|
||||
if (cardSection.validate(card))
|
||||
return cardSection;
|
||||
}
|
||||
@@ -1017,51 +1022,21 @@ public class DeckRecognizer {
|
||||
private static MagicColor.Color getMagicColor(String colorName){
|
||||
if (colorName.toLowerCase().startsWith("multi") || colorName.equalsIgnoreCase("m"))
|
||||
return null; // will be handled separately
|
||||
|
||||
byte color = MagicColor.fromName(colorName.toLowerCase());
|
||||
switch (color) {
|
||||
case MagicColor.WHITE:
|
||||
return MagicColor.Color.WHITE;
|
||||
case MagicColor.BLUE:
|
||||
return MagicColor.Color.BLUE;
|
||||
case MagicColor.BLACK:
|
||||
return MagicColor.Color.BLACK;
|
||||
case MagicColor.RED:
|
||||
return MagicColor.Color.RED;
|
||||
case MagicColor.GREEN:
|
||||
return MagicColor.Color.GREEN;
|
||||
default:
|
||||
return MagicColor.Color.COLORLESS;
|
||||
|
||||
}
|
||||
return MagicColor.Color.fromByte(MagicColor.fromName(colorName.toLowerCase()));
|
||||
}
|
||||
|
||||
public static String getLocalisedMagicColorName(String colorName){
|
||||
Localizer localizer = Localizer.getInstance();
|
||||
switch(colorName.toLowerCase()){
|
||||
case MagicColor.Constant.WHITE:
|
||||
return localizer.getMessage("lblWhite");
|
||||
|
||||
case MagicColor.Constant.BLUE:
|
||||
return localizer.getMessage("lblBlue");
|
||||
|
||||
case MagicColor.Constant.BLACK:
|
||||
return localizer.getMessage("lblBlack");
|
||||
|
||||
case MagicColor.Constant.RED:
|
||||
return localizer.getMessage("lblRed");
|
||||
|
||||
case MagicColor.Constant.GREEN:
|
||||
return localizer.getMessage("lblGreen");
|
||||
|
||||
case MagicColor.Constant.COLORLESS:
|
||||
return localizer.getMessage("lblColorless");
|
||||
case "multicolour":
|
||||
case "multicolor":
|
||||
return localizer.getMessage("lblMulticolor");
|
||||
default:
|
||||
return "";
|
||||
}
|
||||
return switch (colorName.toLowerCase()) {
|
||||
case MagicColor.Constant.WHITE -> localizer.getMessage("lblWhite");
|
||||
case MagicColor.Constant.BLUE -> localizer.getMessage("lblBlue");
|
||||
case MagicColor.Constant.BLACK -> localizer.getMessage("lblBlack");
|
||||
case MagicColor.Constant.RED -> localizer.getMessage("lblRed");
|
||||
case MagicColor.Constant.GREEN -> localizer.getMessage("lblGreen");
|
||||
case MagicColor.Constant.COLORLESS -> localizer.getMessage("lblColorless");
|
||||
case "multicolour", "multicolor" -> localizer.getMessage("lblMulticolor");
|
||||
default -> "";
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1080,37 +1055,6 @@ public class DeckRecognizer {
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
|
||||
private static Pair<String, String> getManaNameAndSymbol(String matchedMana) {
|
||||
if (matchedMana == null)
|
||||
return null;
|
||||
|
||||
Localizer localizer = Localizer.getInstance();
|
||||
switch (matchedMana.toLowerCase()) {
|
||||
case MagicColor.Constant.WHITE:
|
||||
case "w":
|
||||
return Pair.of(localizer.getMessage("lblWhite"), MagicColor.Color.WHITE.getSymbol());
|
||||
case MagicColor.Constant.BLUE:
|
||||
case "u":
|
||||
return Pair.of(localizer.getMessage("lblBlue"), MagicColor.Color.BLUE.getSymbol());
|
||||
case MagicColor.Constant.BLACK:
|
||||
case "b":
|
||||
return Pair.of(localizer.getMessage("lblBlack"), MagicColor.Color.BLACK.getSymbol());
|
||||
case MagicColor.Constant.RED:
|
||||
case "r":
|
||||
return Pair.of(localizer.getMessage("lblRed"), MagicColor.Color.RED.getSymbol());
|
||||
case MagicColor.Constant.GREEN:
|
||||
case "g":
|
||||
return Pair.of(localizer.getMessage("lblGreen"), MagicColor.Color.GREEN.getSymbol());
|
||||
case MagicColor.Constant.COLORLESS:
|
||||
case "c":
|
||||
return Pair.of(localizer.getMessage("lblColorless"), MagicColor.Color.COLORLESS.getSymbol());
|
||||
default: // Multicolour
|
||||
return Pair.of(localizer.getMessage("lblMulticolor"), "");
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean isDeckName(final String lineAsIs) {
|
||||
if (lineAsIs == null)
|
||||
return false;
|
||||
|
||||
@@ -68,7 +68,7 @@ public class AddBasicLandsDialog {
|
||||
private static final int LAND_PANEL_PADDING = 3;
|
||||
|
||||
private final FComboBoxPanel<CardEdition> cbLandSet = new FComboBoxPanel<>(Localizer.getInstance().getMessage("lblLandSet") + ":", FlowLayout.CENTER,
|
||||
IterableUtil.filter(StaticData.instance().getSortedEditions(), CardEdition.Predicates.hasBasicLands));
|
||||
IterableUtil.filter(StaticData.instance().getSortedEditions(), CardEdition::hasBasicLands));
|
||||
|
||||
private final MainPanel panel = new MainPanel();
|
||||
private final LandPanel pnlPlains = new LandPanel("Plains");
|
||||
|
||||
@@ -46,7 +46,6 @@ import forge.toolbox.*;
|
||||
import forge.util.Localizer;
|
||||
import forge.view.FDialog;
|
||||
import net.miginfocom.swing.MigLayout;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import static forge.deck.DeckRecognizer.TokenType.*;
|
||||
|
||||
@@ -523,7 +522,7 @@ public class DeckImport<TModel extends DeckBase> extends FDialog {
|
||||
else
|
||||
deck.setName(currentDeckName);
|
||||
}
|
||||
host.getDeckController().loadDeck(deck, controller.getCreateNewDeck());
|
||||
host.getDeckController().loadDeck(deck, controller.getImportBehavior() != DeckImportController.ImportBehavior.MERGE);
|
||||
processWindowEvent(new WindowEvent(DeckImport.this, WindowEvent.WINDOW_CLOSING));
|
||||
});
|
||||
|
||||
@@ -531,7 +530,7 @@ public class DeckImport<TModel extends DeckBase> extends FDialog {
|
||||
this.createNewDeckCheckbox.setSelected(false);
|
||||
this.createNewDeckCheckbox.addActionListener(e -> {
|
||||
boolean createNewDeck = createNewDeckCheckbox.isSelected();
|
||||
controller.setCreateNewDeck(createNewDeck);
|
||||
controller.setImportBehavior(createNewDeck ? DeckImportController.ImportBehavior.CREATE_NEW : DeckImportController.ImportBehavior.MERGE);
|
||||
String cmdAcceptLabel = createNewDeck ? CREATE_NEW_DECK_CMD_LABEL : IMPORT_CARDS_CMD_LABEL;
|
||||
cmdAcceptButton.setText(cmdAcceptLabel);
|
||||
String smartCardArtChboxTooltip = createNewDeck ? SMART_CARDART_TT_NO_DECK : SMART_CARDART_TT_WITH_DECK;
|
||||
@@ -600,7 +599,7 @@ public class DeckImport<TModel extends DeckBase> extends FDialog {
|
||||
if (token.getType() == LIMITED_CARD)
|
||||
cssClass = WARN_MSG_CLASS;
|
||||
String statusMsg = String.format("<span class=\"%s\" style=\"font-size: 9px;\">%s</span>", cssClass,
|
||||
getTokenStatusMessage(token));
|
||||
controller.getTokenStatusMessage(token));
|
||||
statusLbl.append(statusMsg);
|
||||
}
|
||||
|
||||
@@ -740,12 +739,12 @@ public class DeckImport<TModel extends DeckBase> extends FDialog {
|
||||
private String toHTML(final DeckRecognizer.Token token) {
|
||||
if (token == null)
|
||||
return "";
|
||||
String tokenMsg = getTokenMessage(token);
|
||||
String tokenMsg = controller.getTokenMessage(token);
|
||||
if (tokenMsg == null)
|
||||
return "";
|
||||
String tokenStatus = getTokenStatusMessage(token);
|
||||
String tokenStatus = controller.getTokenStatusMessage(token);
|
||||
String cssClass = getTokenCSSClass(token.getType());
|
||||
if (tokenStatus.length() == 0)
|
||||
if (tokenStatus.isEmpty())
|
||||
tokenMsg = padEndWithHTMLSpaces(tokenMsg, 2*PADDING_TOKEN_MSG_LENGTH+10);
|
||||
else {
|
||||
tokenMsg = padEndWithHTMLSpaces(tokenMsg, PADDING_TOKEN_MSG_LENGTH);
|
||||
@@ -755,11 +754,6 @@ public class DeckImport<TModel extends DeckBase> extends FDialog {
|
||||
tokenMsg = String.format("<a class=\"%s\" href=\"%s\">%s</a>", cssClass,
|
||||
token.getKey().toString(), tokenMsg);
|
||||
|
||||
if (tokenStatus == null) {
|
||||
String tokenTag = String.format("<td colspan=\"2\" class=\"%s\">%s</td>", cssClass, tokenMsg);
|
||||
return String.format("<tr>%s</tr>", tokenTag);
|
||||
}
|
||||
|
||||
String tokenTag = "<td class=\"%s\">%s</td>";
|
||||
String tokenMsgTag = String.format(tokenTag, cssClass, tokenMsg);
|
||||
String tokenStatusTag;
|
||||
@@ -776,97 +770,6 @@ public class DeckImport<TModel extends DeckBase> extends FDialog {
|
||||
return String.format("%s%s", targetMsg, spacer);
|
||||
}
|
||||
|
||||
private String getTokenMessage(DeckRecognizer.Token token) {
|
||||
switch (token.getType()) {
|
||||
case LEGAL_CARD:
|
||||
case LIMITED_CARD:
|
||||
case CARD_FROM_NOT_ALLOWED_SET:
|
||||
case CARD_FROM_INVALID_SET:
|
||||
return String.format("%s x %s %s", token.getQuantity(), token.getText(), getTokenFoilLabel(token));
|
||||
// Card Warning Msgs
|
||||
case UNKNOWN_CARD:
|
||||
case UNSUPPORTED_CARD:
|
||||
return token.getQuantity() > 0 ? String.format("%s x %s", token.getQuantity(), token.getText())
|
||||
: token.getText();
|
||||
|
||||
case UNSUPPORTED_DECK_SECTION:
|
||||
return String.format("%s: %s", Localizer.getInstance().getMessage("lblWarningMsgPrefix"),
|
||||
Localizer.getInstance()
|
||||
.getMessage("lblWarnDeckSectionNotAllowedInEditor", token.getText(),
|
||||
this.currentGameType));
|
||||
|
||||
// Special Case of Card moved into another section (e.g. Commander from Sideboard)
|
||||
case WARNING_MESSAGE:
|
||||
return String.format("%s: %s", Localizer.getInstance()
|
||||
.getMessage("lblWarningMsgPrefix"), token.getText());
|
||||
|
||||
// Placeholders
|
||||
case DECK_SECTION_NAME:
|
||||
return String.format("%s: %s", Localizer.getInstance().getMessage("lblDeckSection"),
|
||||
token.getText());
|
||||
|
||||
case CARD_RARITY:
|
||||
return String.format("%s: %s", Localizer.getInstance().getMessage("lblRarity"),
|
||||
token.getText());
|
||||
|
||||
case CARD_TYPE:
|
||||
case CARD_CMC:
|
||||
case MANA_COLOUR:
|
||||
case COMMENT:
|
||||
return token.getText();
|
||||
|
||||
case DECK_NAME:
|
||||
return String.format("%s: %s", Localizer.getInstance().getMessage("lblDeckName"),
|
||||
token.getText());
|
||||
|
||||
case UNKNOWN_TEXT:
|
||||
default:
|
||||
return null;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private String getTokenStatusMessage(DeckRecognizer.Token token){
|
||||
if (token == null)
|
||||
return "";
|
||||
|
||||
switch (token.getType()) {
|
||||
case LIMITED_CARD:
|
||||
return String.format("%s: %s", Localizer.getInstance().getMessage("lblWarningMsgPrefix"),
|
||||
Localizer.getInstance().getMessage("lblWarnLimitedCard",
|
||||
StringUtils.capitalize(token.getLimitedCardType().name()), getGameFormatLabel()));
|
||||
|
||||
case CARD_FROM_NOT_ALLOWED_SET:
|
||||
return Localizer.getInstance().getMessage("lblErrNotAllowedCard", getGameFormatLabel());
|
||||
|
||||
case CARD_FROM_INVALID_SET:
|
||||
return Localizer.getInstance().getMessage("lblErrCardEditionDate");
|
||||
|
||||
case UNSUPPORTED_CARD:
|
||||
return Localizer.getInstance().getMessage("lblErrUnsupportedCard", this.currentGameType);
|
||||
|
||||
case UNKNOWN_CARD:
|
||||
return String.format("%s: %s", Localizer.getInstance().getMessage("lblWarningMsgPrefix"),
|
||||
Localizer.getInstance().getMessage("lblWarnUnknownCardMsg"));
|
||||
|
||||
case UNSUPPORTED_DECK_SECTION:
|
||||
case WARNING_MESSAGE:
|
||||
case COMMENT:
|
||||
case CARD_CMC:
|
||||
case MANA_COLOUR:
|
||||
case CARD_TYPE:
|
||||
case DECK_SECTION_NAME:
|
||||
case CARD_RARITY:
|
||||
case DECK_NAME:
|
||||
case LEGAL_CARD:
|
||||
case UNKNOWN_TEXT:
|
||||
default:
|
||||
return "";
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private String getTokenCSSClass(DeckRecognizer.TokenType tokenType){
|
||||
switch (tokenType){
|
||||
case LEGAL_CARD:
|
||||
@@ -899,17 +802,6 @@ public class DeckImport<TModel extends DeckBase> extends FDialog {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
private String getTokenFoilLabel(DeckRecognizer.Token token) {
|
||||
if (!token.isCardToken())
|
||||
return "";
|
||||
final String foilMarker = "- (Foil)";
|
||||
return token.getCard().isFoil() ? foilMarker : "";
|
||||
}
|
||||
|
||||
private String getGameFormatLabel() {
|
||||
return String.format("\"%s\"", this.controller.getCurrentGameFormatName());
|
||||
}
|
||||
}
|
||||
|
||||
class GameFormatDropdownRenderer extends JLabel implements ListCellRenderer<GameFormat> {
|
||||
|
||||
@@ -27,8 +27,6 @@ import forge.item.PaperCard;
|
||||
import forge.itemmanager.*;
|
||||
import forge.itemmanager.filters.CardColorFilter;
|
||||
import forge.itemmanager.filters.CardTypeFilter;
|
||||
import forge.localinstance.properties.ForgePreferences;
|
||||
import forge.menu.FCheckBoxMenuItem;
|
||||
import forge.menu.FDropDownMenu;
|
||||
import forge.menu.FMenuItem;
|
||||
import forge.menu.FPopupMenu;
|
||||
@@ -41,6 +39,7 @@ import forge.util.Utils;
|
||||
import java.util.*;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
public class AdventureDeckEditor extends FDeckEditor {
|
||||
protected static class AdventureEditorConfig extends DeckEditorConfig {
|
||||
@@ -146,7 +145,8 @@ public class AdventureDeckEditor extends FDeckEditor {
|
||||
if(event.cardBlock != null) {
|
||||
if(event.cardBlock.getLandSet() != null)
|
||||
return List.of(event.cardBlock.getLandSet());
|
||||
List<CardEdition> eventSets = event.cardBlock.getSets();
|
||||
List<CardEdition> eventSets = new ArrayList<>(event.cardBlock.getSets());
|
||||
eventSets.removeIf(Predicate.not(CardEdition::hasBasicLands));
|
||||
if(!eventSets.isEmpty())
|
||||
return eventSets;
|
||||
}
|
||||
@@ -558,7 +558,7 @@ public class AdventureDeckEditor extends FDeckEditor {
|
||||
currentEvent.participants[i].setDeck(opponentDecks[i]);
|
||||
}
|
||||
currentEvent.draftedDeck = (Deck) currentEvent.registeredDeck.copyTo("Draft Deck");
|
||||
if (allowsAddBasic()) {
|
||||
if (allowAddBasic()) {
|
||||
showAddBasicLandsDialog();
|
||||
//Might be annoying if you haven't pruned your deck yet, but best to remind player that
|
||||
//this probably needs to be done since it's there since it's not normally part of Adventure
|
||||
@@ -713,27 +713,6 @@ public class AdventureDeckEditor extends FDeckEditor {
|
||||
return this.deckHeader;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected FPopupMenu createMoreOptionsMenu() {
|
||||
return new FPopupMenu() {
|
||||
@Override
|
||||
protected void buildMenu() {
|
||||
Localizer localizer = Forge.getLocalizer();
|
||||
addItem(new FMenuItem(localizer.getMessage("btnCopyToClipboard"), Forge.hdbuttons ? FSkinImage.HDEXPORT : FSkinImage.BLANK, e1 -> FDeckViewer.copyDeckToClipboard(getDeck())));
|
||||
if (allowsAddBasic()) {
|
||||
FMenuItem addBasic = new FMenuItem(localizer.getMessage("lblAddBasicLands"), FSkinImage.LANDLOGO, e1 -> showAddBasicLandsDialog());
|
||||
addItem(addBasic);
|
||||
}
|
||||
if(FModel.getPreferences().getPrefBoolean(ForgePreferences.FPref.DEV_MODE_ENABLED)) {
|
||||
addItem(new FCheckBoxMenuItem(localizer.getMessage("cbEnforceDeckLegality"), shouldEnforceConformity(), e -> toggleConformity()));
|
||||
String devSuffix = " (" + localizer.getMessage("lblDev") + ")";
|
||||
addItem(new FMenuItem(localizer.getMessage("lblAddcard") + devSuffix, FSkinImage.HDPLUS, e -> showDevAddCardDialog()));
|
||||
}
|
||||
((DeckEditorPage) getSelectedPage()).buildDeckMenu(this);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void addChosenBasicLands(CardPool landsToAdd) {
|
||||
if(isLimitedEditor())
|
||||
@@ -765,6 +744,12 @@ public class AdventureDeckEditor extends FDeckEditor {
|
||||
catalog.moveCards(landsToMove, getMainDeckPage());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected PaperCard supplyPrintForImporter(PaperCard missingCard) {
|
||||
PaperCard out = super.supplyPrintForImporter(missingCard);
|
||||
return out == null ? null : out.getNoSellVersion();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void cacheTabPages() {
|
||||
super.cacheTabPages();
|
||||
@@ -775,7 +760,9 @@ public class AdventureDeckEditor extends FDeckEditor {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean allowsAddBasic() {
|
||||
protected boolean allowAddBasic() {
|
||||
if(getEditorConfig() instanceof DeckPreviewConfig)
|
||||
return false;
|
||||
AdventureEventData currentEvent = getCurrentEvent();
|
||||
if (currentEvent == null)
|
||||
return true;
|
||||
|
||||
@@ -59,7 +59,7 @@ public class AddBasicLandsDialog extends FDialog {
|
||||
private final Consumer<CardPool> callback;
|
||||
|
||||
private final FLabel lblLandSet = add(new FLabel.Builder().text(Forge.getLocalizer().getMessage("lblLandSet") + ":").font(FSkinFont.get(12)).textColor(FLabel.getInlineLabelColor()).build());
|
||||
private final FComboBox<CardEdition> cbLandSet = add(new FComboBox<>(IterableUtil.filter(StaticData.instance().getEditions(), CardEdition.Predicates.hasBasicLands)));
|
||||
private final FComboBox<CardEdition> cbLandSet = add(new FComboBox<>(IterableUtil.filter(StaticData.instance().getSortedEditions(), CardEdition::hasBasicLands)));
|
||||
|
||||
private final FScrollPane scroller = add(new FScrollPane() {
|
||||
@Override
|
||||
|
||||
@@ -81,13 +81,21 @@ public class FDeckEditor extends TabPageScreen<FDeckEditor> {
|
||||
public boolean allowsCardReplacement() { return hasInfiniteCardPool() || usePlayerInventory(); }
|
||||
|
||||
public List<CardEdition> getBasicLandSets(Deck currentDeck) {
|
||||
if(hasInfiniteCardPool())
|
||||
return FModel.getMagicDb().getSortedEditions().stream().filter(CardEdition::hasBasicLands).collect(Collectors.toList());
|
||||
return List.of(DeckProxy.getDefaultLandSet(currentDeck));
|
||||
}
|
||||
|
||||
protected abstract IDeckController getController();
|
||||
protected abstract DeckEditorPage[] getInitialPages();
|
||||
|
||||
protected DeckSection[] getExtraSections() {
|
||||
public DeckSection[] getPrimarySections() {
|
||||
if(getGameType() != null)
|
||||
return getGameType().getPrimaryDeckSections().toArray(new DeckSection[0]);
|
||||
return new DeckSection[]{DeckSection.Main, DeckSection.Sideboard};
|
||||
}
|
||||
|
||||
public DeckSection[] getExtraSections() {
|
||||
if(getGameType() != null)
|
||||
return getGameType().getSupplimentalDeckSections().toArray(new DeckSection[0]);
|
||||
return new DeckSection[]{DeckSection.Attractions, DeckSection.Contraptions};
|
||||
@@ -144,7 +152,7 @@ public class FDeckEditor extends TabPageScreen<FDeckEditor> {
|
||||
ItemManagerConfig catalogConfig = null;
|
||||
ItemManagerConfig mainSectionConfig = null;
|
||||
ItemManagerConfig sideboardConfig = null;
|
||||
Function<Deck, CardEdition> fnGetBasicLandSet = null;
|
||||
Function<Deck, Collection<CardEdition>> fnGetBasicLandSet = null;
|
||||
Supplier<ItemPool<PaperCard>> itemPoolSupplier = null;
|
||||
String catalogCaption = null;
|
||||
|
||||
@@ -196,7 +204,7 @@ public class FDeckEditor extends TabPageScreen<FDeckEditor> {
|
||||
this.sideboardConfig = sideboardConfig;
|
||||
return this;
|
||||
}
|
||||
public GameTypeDeckEditorConfig setBasicLandSetFunction(Function<Deck, CardEdition> fnGetBasicLandSet) {
|
||||
public GameTypeDeckEditorConfig setBasicLandSetFunction(Function<Deck, Collection<CardEdition>> fnGetBasicLandSet) {
|
||||
this.fnGetBasicLandSet = fnGetBasicLandSet;
|
||||
return this;
|
||||
}
|
||||
@@ -296,9 +304,21 @@ public class FDeckEditor extends TabPageScreen<FDeckEditor> {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected DeckSection[] getExtraSections() {
|
||||
public DeckSection[] getPrimarySections() {
|
||||
return gameType.getPrimaryDeckSections().toArray(new DeckSection[0]);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DeckSection[] getExtraSections() {
|
||||
return gameType.getSupplimentalDeckSections().toArray(new DeckSection[0]);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<CardEdition> getBasicLandSets(Deck currentDeck) {
|
||||
if(this.fnGetBasicLandSet != null)
|
||||
return List.copyOf(fnGetBasicLandSet.apply(currentDeck));
|
||||
return super.getBasicLandSets(currentDeck);
|
||||
}
|
||||
}
|
||||
|
||||
public static DeckEditorConfig EditorConfigConstructed = new GameTypeDeckEditorConfig(GameType.Constructed,
|
||||
@@ -348,18 +368,19 @@ public class FDeckEditor extends TabPageScreen<FDeckEditor> {
|
||||
.setMainSectionConfig(ItemManagerConfig.QUEST_DECK_EDITOR)
|
||||
.setSideboardConfig(ItemManagerConfig.QUEST_DECK_EDITOR)
|
||||
.setPlayerInventorySupplier(() -> FModel.getQuest().getCards().getCardpool())
|
||||
.setBasicLandSetFunction(d -> FModel.getQuest().getDefaultLandSet());
|
||||
.setBasicLandSetFunction(d -> FModel.getQuest().getAvailableLandSets());
|
||||
public static DeckEditorConfig EditorConfigQuestCommander = new GameTypeDeckEditorConfig(GameType.QuestCommander, DECK_CONTROLLER_QUEST)
|
||||
.setCatalogConfig(ItemManagerConfig.QUEST_EDITOR_POOL)
|
||||
.setMainSectionConfig(ItemManagerConfig.QUEST_DECK_EDITOR)
|
||||
.setSideboardConfig(ItemManagerConfig.QUEST_DECK_EDITOR)
|
||||
.setPlayerInventorySupplier(() -> FModel.getQuest().getCards().getCardpool())
|
||||
.setBasicLandSetFunction(d -> FModel.getQuest().getDefaultLandSet());
|
||||
.setBasicLandSetFunction(d -> FModel.getQuest().getAvailableLandSets());
|
||||
public static DeckEditorConfig EditorConfigQuestDraft = new GameTypeDeckEditorConfig(GameType.QuestDraft, DECK_CONTROLLER_QUEST_DRAFT);
|
||||
public static DeckEditorConfig EditorConfigPlanarConquest = new GameTypeDeckEditorConfig(GameType.PlanarConquest, DECK_CONTROLLER_PLANAR_CONQUEST)
|
||||
.setCatalogConfig(ItemManagerConfig.CONQUEST_COLLECTION)
|
||||
.setMainSectionConfig(ItemManagerConfig.CONQUEST_DECK_EDITOR)
|
||||
.setPlayerInventorySupplier(ConquestUtil::getAvailablePool);
|
||||
.setPlayerInventorySupplier(ConquestUtil::getAvailablePool)
|
||||
.setBasicLandSetFunction(ConquestUtil::getBasicLandSets);
|
||||
|
||||
protected static DeckSectionPage createPageForExtraSection(DeckSection deckSection, DeckEditorConfig editorConfig) {
|
||||
CardManager cm = new CardManager(false);
|
||||
@@ -542,7 +563,7 @@ public class FDeckEditor extends TabPageScreen<FDeckEditor> {
|
||||
@Override
|
||||
protected void buildMenu() {
|
||||
final Localizer localizer = Forge.getLocalizer();
|
||||
if (allowsAddBasic())
|
||||
if (allowAddBasic())
|
||||
addItem(new FMenuItem(localizer.getMessage("lblAddBasicLands"), FSkinImage.LANDLOGO, e -> showAddBasicLandsDialog()));
|
||||
if (showAddExtraSectionOption()) {
|
||||
addItem(new FMenuItem(localizer.getMessage("lblAddDeckSection"), FSkinImage.CHAOS, e -> {
|
||||
@@ -558,28 +579,41 @@ public class FDeckEditor extends TabPageScreen<FDeckEditor> {
|
||||
});
|
||||
}));
|
||||
}
|
||||
if (editorConfig.getGameType() != null && editorConfig.hasInfiniteCardPool()) {
|
||||
if (editorConfig.hasInfiniteCardPool() || editorConfig.usePlayerInventory()) {
|
||||
addItem(new FMenuItem(localizer.getMessage("lblImportFromClipboard"), Forge.hdbuttons ? FSkinImage.HDIMPORT : FSkinImage.OPEN, e -> {
|
||||
FDeckImportDialog dialog = new FDeckImportDialog(!deck.isEmpty(), FDeckEditor.this.editorConfig);
|
||||
FDeckImportDialog dialog = new FDeckImportDialog(deck, FDeckEditor.this.editorConfig);
|
||||
if(editorConfig.usePlayerInventory())
|
||||
dialog.setFreePrintConverter(FDeckEditor.this::supplyPrintForImporter);
|
||||
dialog.setImportBannedCards(!FModel.getPreferences().getPrefBoolean(FPref.ENFORCE_DECK_LEGALITY));
|
||||
dialog.setCallback(importedDeck -> {
|
||||
if (deck != null && importedDeck.hasName()) {
|
||||
deck.setName(importedDeck.getName());
|
||||
setHeaderText(importedDeck.getName());
|
||||
}
|
||||
if (dialog.createNewDeck()) {
|
||||
for (Entry<DeckSection, CardPool> section : importedDeck) {
|
||||
DeckSectionPage page = getPageForSection(section.getKey());
|
||||
if (page != null)
|
||||
page.setCards(section.getValue());
|
||||
}
|
||||
} else {
|
||||
for (Entry<DeckSection, CardPool> section : importedDeck) {
|
||||
DeckSectionPage page = getPageForSection(section.getKey());
|
||||
if (page != null)
|
||||
page.addCards(section.getValue());
|
||||
}
|
||||
switch (dialog.getImportBehavior()) {
|
||||
case REPLACE_CURRENT:
|
||||
for(DeckSectionPage page : pagesBySection.values()) {
|
||||
if(importedDeck.has(page.deckSection)) {
|
||||
page.setCards(importedDeck.get(page.deckSection));
|
||||
if(hiddenExtraSections.contains(page.deckSection))
|
||||
showExtraSectionTab(page.deckSection);
|
||||
}
|
||||
else
|
||||
page.setCards(new CardPool());
|
||||
}
|
||||
break;
|
||||
case CREATE_NEW:
|
||||
deckController.setDeck(importedDeck);
|
||||
break;
|
||||
case MERGE:
|
||||
for (Entry<DeckSection, CardPool> section : importedDeck) {
|
||||
DeckSectionPage page = getPageForSection(section.getKey());
|
||||
if (page != null)
|
||||
page.addCards(section.getValue());
|
||||
}
|
||||
}
|
||||
});
|
||||
dialog.initParse();
|
||||
dialog.show();
|
||||
setSelectedPage(getMainDeckPage()); //select main deck page if needed so main deck if visible below dialog
|
||||
}));
|
||||
@@ -643,6 +677,20 @@ public class FDeckEditor extends TabPageScreen<FDeckEditor> {
|
||||
getMainDeckPage().addCards(landsToAdd);
|
||||
}
|
||||
|
||||
/**
|
||||
* If a card is missing from a player's inventory while importing a deck, it gets run through here.
|
||||
* Returning a PaperCard will let unlimited copies of that card be used as a substitute. Returning null
|
||||
* will leave the card missing from the import.
|
||||
*/
|
||||
protected PaperCard supplyPrintForImporter(PaperCard missingCard) {
|
||||
//Could support dungeons here too? Not that we really use them in the editor...
|
||||
if(!missingCard.isVeryBasicLand())
|
||||
return null;
|
||||
List<CardEdition> basicSets = editorConfig.getBasicLandSets(deck);
|
||||
String setCode = basicSets.isEmpty() ? "JMP" : basicSets.get(0).getCode();
|
||||
return FModel.getMagicDb().fetchCard(missingCard.getCardName(), setCode, null);
|
||||
}
|
||||
|
||||
protected boolean shouldEnforceConformity() {
|
||||
if(FModel.getPreferences().getPrefBoolean(FPref.ENFORCE_DECK_LEGALITY))
|
||||
return true;
|
||||
@@ -695,6 +743,9 @@ public class FDeckEditor extends TabPageScreen<FDeckEditor> {
|
||||
showExtraSectionTab(section);
|
||||
if(pagesBySection.containsKey(section))
|
||||
setSelectedPage(pagesBySection.get(section));
|
||||
else if(section == DeckSection.Main && pagesBySection.containsKey(mainDeckPage.deckSection))
|
||||
//Tried to switch to the Main page in a Planar or Scheme deck.
|
||||
setSelectedPage(pagesBySection.get(mainDeckPage.deckSection));
|
||||
}
|
||||
|
||||
public void notifyNewControllerModel() {
|
||||
@@ -1027,7 +1078,7 @@ public class FDeckEditor extends TabPageScreen<FDeckEditor> {
|
||||
protected boolean allowSaveAs() {
|
||||
return allowSave() && allowRename();
|
||||
}
|
||||
protected boolean allowsAddBasic() {
|
||||
protected boolean allowAddBasic() {
|
||||
return !isDrafting();
|
||||
}
|
||||
|
||||
|
||||
@@ -18,11 +18,12 @@
|
||||
package forge.deck;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.EnumSet;
|
||||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.Lists;
|
||||
|
||||
import forge.Forge;
|
||||
import forge.Graphics;
|
||||
@@ -31,11 +32,15 @@ import forge.deck.DeckRecognizer.TokenType;
|
||||
import forge.game.GameType;
|
||||
import forge.gui.FThreads;
|
||||
import forge.gui.util.SOptionPane;
|
||||
import forge.item.PaperCard;
|
||||
import forge.toolbox.FCheckBox;
|
||||
import forge.toolbox.FComboBox;
|
||||
import forge.toolbox.FDialog;
|
||||
import forge.toolbox.FOptionPane;
|
||||
import forge.toolbox.FTextArea;
|
||||
import forge.util.ItemPool;
|
||||
import forge.util.Localizer;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
|
||||
public class FDeckImportDialog extends FDialog {
|
||||
@@ -45,7 +50,7 @@ public class FDeckImportDialog extends FDialog {
|
||||
private final FCheckBox newEditionCheck = add(new FCheckBox(Forge.getLocalizer().getMessage("lblImportLatestVersionCard"), false));
|
||||
private final FCheckBox dateTimeCheck = add(new FCheckBox(Forge.getLocalizer().getMessage("lblUseOnlySetsReleasedBefore"), false));
|
||||
private final FCheckBox smartCardArtCheck = add(new FCheckBox(Forge.getLocalizer().getMessage("lblUseSmartCardArt"), false));
|
||||
private final FCheckBox createNewDeckCheck = add(new FCheckBox(Forge.getLocalizer().getMessage("lblNewDeckCheckbox"), false));
|
||||
private final FCheckBox createNewDeckCheck = add(new FCheckBox(Forge.getLocalizer().getMessage("lblReplaceDeckCheckbox"), false));
|
||||
// private final FCheckBox importInDeck = add(new FCheckBox()
|
||||
/*setting onlyCoreExpCheck to false allow the copied cards to pass the check of deck contents
|
||||
forge-core\src\main\java\forge\deck\Deck.javaDeck.java starting @ Line 320 which is called by
|
||||
@@ -57,100 +62,60 @@ public class FDeckImportDialog extends FDialog {
|
||||
private final FComboBox<String> monthDropdown = add(new FComboBox<>()); //don't need wrappers since skin can't change while this dialog is open
|
||||
private final FComboBox<Integer> yearDropdown = add(new FComboBox<>());
|
||||
|
||||
private final boolean showOptions;
|
||||
private final boolean currentDeckIsEmpty;
|
||||
private boolean showOptions;
|
||||
private final Deck currentDeck;
|
||||
private boolean createNewDeckControl;
|
||||
private final DeckImportController controller;
|
||||
private final FDeckEditor.DeckEditorConfig editorConfig;
|
||||
|
||||
private final static ImmutableList<String> importOrCancel = ImmutableList.of(Forge.getLocalizer().getMessage("lblImport"), Forge.getLocalizer().getMessage("lblCancel"));
|
||||
|
||||
public FDeckImportDialog(final boolean replacingDeck, final FDeckEditor.DeckEditorConfig editorConfig) {
|
||||
public FDeckImportDialog(final Deck currentDeck, final FDeckEditor.DeckEditorConfig editorConfig) {
|
||||
super(Forge.getLocalizer().getMessage("lblImportFromClipboard"), 2);
|
||||
boolean usingInventory = editorConfig.usePlayerInventory();
|
||||
boolean replacingDeck = !currentDeck.isEmpty() || usingInventory;
|
||||
this.currentDeck = currentDeck;
|
||||
this.editorConfig = editorConfig;
|
||||
ItemPool<PaperCard> cardPool = editorConfig.getCardPool(false);
|
||||
controller = new DeckImportController(dateTimeCheck, monthDropdown, yearDropdown, replacingDeck);
|
||||
String contents = Forge.getClipboard().getContents();
|
||||
if (contents == null)
|
||||
contents = ""; //prevent NPE
|
||||
txtInput.setText(contents);
|
||||
|
||||
if (editorConfig.allowsCardReplacement()) {
|
||||
GameType gameType = editorConfig.getGameType();
|
||||
controller.setGameFormat(gameType);
|
||||
List<DeckSection> supportedSections = new ArrayList<>();
|
||||
supportedSections.add(DeckSection.Main);
|
||||
supportedSections.add(DeckSection.Sideboard);
|
||||
if (editorConfig.hasCommander())
|
||||
supportedSections.add(DeckSection.Commander);
|
||||
supportedSections.addAll(Lists.newArrayList(editorConfig.getExtraSections()));
|
||||
controller.setAllowedSections(supportedSections);
|
||||
}
|
||||
GameType gameType = editorConfig.getGameType();
|
||||
controller.setGameFormat(gameType);
|
||||
List<DeckSection> supportedSections = new ArrayList<>();
|
||||
supportedSections.addAll(List.of(editorConfig.getPrimarySections()));
|
||||
supportedSections.addAll(List.of(editorConfig.getExtraSections()));
|
||||
controller.setAllowedSections(supportedSections);
|
||||
controller.setCurrentDeckInEditor(currentDeck);
|
||||
if(usingInventory)
|
||||
controller.setPlayerInventory(cardPool);
|
||||
|
||||
onlyCoreExpCheck.setSelected(StaticData.instance().isCoreExpansionOnlyFilterSet());
|
||||
newEditionCheck.setSelected(StaticData.instance().cardArtPreferenceIsLatest());
|
||||
smartCardArtCheck.setSelected(StaticData.instance().isEnabledCardArtSmartSelection());
|
||||
createNewDeckCheck.setSelected(replacingDeck);
|
||||
this.currentDeckIsEmpty = !replacingDeck;
|
||||
this.createNewDeckControl = replacingDeck;
|
||||
|
||||
initButton(0, Forge.getLocalizer().getMessage("lblImport"), e -> FThreads.invokeInBackgroundThread(() -> {
|
||||
List<DeckRecognizer.Token> tokens = controller.parseInput(txtInput.getText()); //ensure deck updated based on any changes to options
|
||||
if(usingInventory)
|
||||
controller.setImportBehavior(DeckImportController.ImportBehavior.REPLACE_CURRENT);
|
||||
else
|
||||
controller.setImportBehavior(createNewDeckControl ? DeckImportController.ImportBehavior.CREATE_NEW : DeckImportController.ImportBehavior.MERGE);
|
||||
|
||||
if (controller.isSmartCardArtEnabled())
|
||||
tokens = controller.optimiseCardArtInTokens();
|
||||
|
||||
//if there are any cards that cannot be imported, let user know this and give them the option to cancel
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (DeckRecognizer.Token token : tokens) {
|
||||
if (token.getType() == TokenType.CARD_FROM_NOT_ALLOWED_SET
|
||||
|| token.getType() == TokenType.CARD_FROM_INVALID_SET
|
||||
|| token.getType() == TokenType.UNKNOWN_CARD
|
||||
|| token.getType() == TokenType.UNSUPPORTED_CARD) {
|
||||
if (sb.length() > 0)
|
||||
sb.append("\n");
|
||||
sb.append(token.getQuantity()).append(" ").append(token.getText());
|
||||
}
|
||||
}
|
||||
if (sb.length() > 0) {
|
||||
if (SOptionPane.showOptionDialog(Forge.getLocalizer().getMessage("lblFollowingCardsCannotBeImported") + "\n\n" + sb, Forge.getLocalizer().getMessage("lblImportRemainingCards"), SOptionPane.INFORMATION_ICON, importOrCancel) == 1) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
final Deck deck = controller.accept(); //must accept in background thread in case a dialog is shown
|
||||
if (deck == null) { return; }
|
||||
|
||||
FThreads.invokeInEdtLater(() -> {
|
||||
hide();
|
||||
if (callback != null)
|
||||
callback.accept(deck);
|
||||
});
|
||||
}));
|
||||
initButton(0, Forge.getLocalizer().getMessage("lblImport"), e -> FThreads.invokeInBackgroundThread(this::performImport));
|
||||
initButton(1, Forge.getLocalizer().getMessage("lblCancel"), e -> hide());
|
||||
|
||||
List<DeckRecognizer.Token> tokens = controller.parseInput(txtInput.getText());
|
||||
if (controller.isSmartCardArtEnabled())
|
||||
tokens = controller.optimiseCardArtInTokens();
|
||||
//ensure at least one known card found on clipboard
|
||||
for (DeckRecognizer.Token token : tokens) {
|
||||
if (token.getType() == TokenType.LEGAL_CARD) {
|
||||
showOptions = true;
|
||||
|
||||
dateTimeCheck.setCommand(e -> updateDropDownEnabled());
|
||||
newEditionCheck.setCommand(e -> setArtPreferenceInController());
|
||||
onlyCoreExpCheck.setCommand(e -> setArtPreferenceInController());
|
||||
smartCardArtCheck.setCommand(e -> controller.setSmartCardArtOptimisation(smartCardArtCheck.isSelected()));
|
||||
createNewDeckCheck.setCommand(e -> {
|
||||
createNewDeckControl = createNewDeckCheck.isSelected();
|
||||
controller.setCreateNewDeck(createNewDeckControl);
|
||||
});
|
||||
updateDropDownEnabled();
|
||||
setArtPreferenceInController();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
showOptions = false;
|
||||
setButtonEnabled(0, false);
|
||||
txtInput.setText(Forge.getLocalizer().getMessage("lblNoKnownCardsOnClipboard"));
|
||||
dateTimeCheck.setCommand(e -> updateDropDownEnabled());
|
||||
newEditionCheck.setCommand(e -> setArtPreferenceInController());
|
||||
onlyCoreExpCheck.setCommand(e -> setArtPreferenceInController());
|
||||
smartCardArtCheck.setCommand(e -> controller.setSmartCardArtOptimisation(smartCardArtCheck.isSelected()));
|
||||
createNewDeckCheck.setCommand(e -> {
|
||||
createNewDeckControl = createNewDeckCheck.isSelected();
|
||||
controller.setImportBehavior(createNewDeckControl ? DeckImportController.ImportBehavior.CREATE_NEW : DeckImportController.ImportBehavior.MERGE);
|
||||
});
|
||||
setShowOptions(false);
|
||||
}
|
||||
|
||||
private void setArtPreferenceInController() {
|
||||
@@ -160,16 +125,66 @@ public class FDeckImportDialog extends FDialog {
|
||||
}
|
||||
|
||||
private void updateDropDownEnabled() {
|
||||
boolean enabled = dateTimeCheck.isSelected();
|
||||
boolean enabled = dateTimeCheck.isSelected() && this.showOptions;
|
||||
monthDropdown.setEnabled(enabled);
|
||||
yearDropdown.setEnabled(enabled);
|
||||
}
|
||||
|
||||
private void setShowOptions(boolean showOptions) {
|
||||
this.showOptions = showOptions;
|
||||
dateTimeCheck.setEnabled(showOptions);
|
||||
newEditionCheck.setEnabled(showOptions);
|
||||
onlyCoreExpCheck.setEnabled(showOptions);
|
||||
newEditionCheck.setEnabled(showOptions);
|
||||
smartCardArtCheck.setEnabled(showOptions);
|
||||
createNewDeckCheck.setEnabled(showOptions);
|
||||
updateDropDownEnabled();
|
||||
}
|
||||
|
||||
public void setCallback(Consumer<Deck> callback0){
|
||||
callback = callback0;
|
||||
}
|
||||
|
||||
public boolean createNewDeck(){ return this.createNewDeckControl; }
|
||||
public void setFreePrintConverter(Function<PaperCard, PaperCard> freePrintConverter) {
|
||||
this.controller.setFreePrintConverter(freePrintConverter);
|
||||
}
|
||||
|
||||
public DeckImportController.ImportBehavior getImportBehavior() {
|
||||
return controller.getImportBehavior();
|
||||
}
|
||||
|
||||
public void setImportBannedCards(boolean importBannedCards) {
|
||||
controller.importBannedAndRestrictedCards(importBannedCards);
|
||||
}
|
||||
|
||||
public void initParse() {
|
||||
boolean usingInventory = editorConfig.usePlayerInventory();
|
||||
List<DeckRecognizer.Token> tokens = controller.parseInput(txtInput.getText());
|
||||
if (usingInventory)
|
||||
tokens = controller.constrainTokensToInventory();
|
||||
else if (controller.isSmartCardArtEnabled())
|
||||
tokens = controller.optimiseCardArtInTokens();
|
||||
//ensure at least one known card found on clipboard
|
||||
for (DeckRecognizer.Token token : tokens) {
|
||||
if (token.getType() == TokenType.LEGAL_CARD || token.getType() == TokenType.FREE_CARD_NOT_IN_INVENTORY) {
|
||||
|
||||
if(usingInventory) {
|
||||
//Settings aren't compatible with player inventories.
|
||||
setShowOptions(false);
|
||||
return;
|
||||
}
|
||||
|
||||
setShowOptions(true);
|
||||
|
||||
updateDropDownEnabled();
|
||||
setArtPreferenceInController();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
setButtonEnabled(0, false);
|
||||
txtInput.setText(Forge.getLocalizer().getMessage("lblNoKnownCardsOnClipboard"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawOverlay(Graphics g) {
|
||||
@@ -202,7 +217,7 @@ public class FDeckImportDialog extends FDialog {
|
||||
yearDropdown.setBounds(x + dropDownWidth + fieldPadding, y, dropDownWidth, h);
|
||||
y += h + fieldPadding;
|
||||
|
||||
if (!this.currentDeckIsEmpty){
|
||||
if (!this.currentDeck.isEmpty()){
|
||||
smartCardArtCheck.setBounds(x, y, w/2, h);
|
||||
createNewDeckCheck.setBounds(x + w/2, y, w/2, h);
|
||||
} else
|
||||
@@ -222,4 +237,49 @@ public class FDeckImportDialog extends FDialog {
|
||||
}
|
||||
return y;
|
||||
}
|
||||
|
||||
private static final EnumSet<TokenType> MISSING_TOKENS = EnumSet.of(TokenType.CARD_FROM_NOT_ALLOWED_SET,
|
||||
TokenType.CARD_FROM_INVALID_SET, TokenType.UNKNOWN_CARD, TokenType.UNSUPPORTED_CARD,
|
||||
TokenType.WARNING_MESSAGE, TokenType.CARD_NOT_IN_INVENTORY);
|
||||
|
||||
private void performImport() {
|
||||
List<DeckRecognizer.Token> tokens = controller.parseInput(txtInput.getText()); //ensure deck updated based on any changes to options
|
||||
|
||||
if (editorConfig.usePlayerInventory())
|
||||
tokens = controller.constrainTokensToInventory();
|
||||
else if (controller.isSmartCardArtEnabled())
|
||||
tokens = controller.optimiseCardArtInTokens();
|
||||
|
||||
//if there are any cards that cannot be imported, let user know this and give them the option to cancel
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (DeckRecognizer.Token token : tokens) {
|
||||
if (MISSING_TOKENS.contains(token.getType())) {
|
||||
if (!sb.isEmpty())
|
||||
sb.append("\n");
|
||||
String message = controller.getTokenMessage(token);
|
||||
String statusMessage = controller.getTokenStatusMessage(token);
|
||||
if(!StringUtils.isBlank(statusMessage))
|
||||
sb.append(String.format("%s - (%s)", message, statusMessage));
|
||||
else
|
||||
sb.append(statusMessage);
|
||||
}
|
||||
}
|
||||
if (!sb.isEmpty()) {
|
||||
Localizer localizer = Forge.getLocalizer();
|
||||
if (SOptionPane.showOptionDialog(localizer.getMessage("lblFollowingCardsCannotBeImported") + "\n\n" + sb, localizer.getMessage("lblImportRemainingCards"), SOptionPane.WARNING_ICON, importOrCancel) == 1) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
final Deck deck = controller.accept(currentDeck.getName()); //must accept in background thread in case a dialog is shown
|
||||
if (deck == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
FThreads.invokeInEdtLater(() -> {
|
||||
hide();
|
||||
if (callback != null)
|
||||
callback.accept(deck);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2838,6 +2838,7 @@ lblDecklistTitle=Deckliste
|
||||
lblSummaryStats=Gesamt-Statistik
|
||||
lblDeckSection=Bereich
|
||||
lblNewDeckCheckbox=Erzeuge ein neues Deck
|
||||
lblReplaceDeckCheckbox=Replace Current Deck
|
||||
lblImportCardsCmd=Importiere Karten
|
||||
lblCreateNewCmd=Neues Deck
|
||||
lblErrNotAllowedCard=Set ist nicht erlaubt in {0}
|
||||
@@ -2845,6 +2846,7 @@ lblWarnLimitedCard={0} in {1}
|
||||
lblErrCardEditionDate=Set verträgt sich nicht mit der Erscheinungsdatum-Option
|
||||
lblErrUnsupportedCard=Ist nicht erlaubt in {0}
|
||||
lblWarnUnknownCardMsg=Unbekannte oder in Forge nicht unterstützte Karte
|
||||
lblWarnNotInInventory=Card not found in inventory
|
||||
lblWarnTooManyCommanders=Aktueller {0}-Bereich enthält {1} mögliche Commander-Karten: {2}
|
||||
lblWarnCommandersInSideExtra=Bitte prüfen und, falls nötig, min. eine Karte in den Commander-Bereich verschieben.
|
||||
lblWarnDeckSectionNotAllowedInEditor=In {1} ist der {0}-Bereich nicht erlaubt.
|
||||
@@ -2936,6 +2938,7 @@ lblCardImportWarning=\nWarnung: Das Deck {0} wird umbenannt in {1}.
|
||||
lblConfirmCreateNewDeck=Du bist dabei das neue Deck {0} zu erzeugen. {1}\n\nWillst du fortfahren?\n\n Hinweis: \
|
||||
Bitte denk daran den "Save"-Knopf im Deck-Editor zu klicken, um das neue Deck dem Deck-Katalog hinzuzufügen!
|
||||
lblNewDeckWarning=\nWarnung: Alle ungesicherten Änderungen am aktuellen Deck {0} werden verlorengehen.
|
||||
lblConfirmReplaceDeck=This will replace the contents of the current deck ({0}) with the imported cards.\n\nWould you like to proceed?
|
||||
lblImportCardsDialogTitle=Importiere Karten in aktuelles Deck
|
||||
lblNewDeckDialogTitle=Erzeuge neues Deck
|
||||
#FNetOverlay.java
|
||||
|
||||
@@ -2898,6 +2898,7 @@ lblDecklistTitle=Decklist
|
||||
lblSummaryStats=Summary Statistics
|
||||
lblDeckSection=Section
|
||||
lblNewDeckCheckbox=Create a New Deck
|
||||
lblReplaceDeckCheckbox=Replace Current Deck
|
||||
lblImportCardsCmd=Import Cards
|
||||
lblCreateNewCmd=New Deck
|
||||
lblErrNotAllowedCard=Set not allowed in {0}
|
||||
@@ -2905,6 +2906,7 @@ lblWarnLimitedCard={0} in {1}
|
||||
lblErrCardEditionDate=Set not compliant with Release Date option
|
||||
lblErrUnsupportedCard=Not allowed in {0}
|
||||
lblWarnUnknownCardMsg=Unknown Card or Unsupported in Forge
|
||||
lblWarnNotInInventory=Card not found in inventory
|
||||
lblWarnTooManyCommanders=Current {0} Section contains {1} potential Commander Cards: {2}
|
||||
lblWarnCommandersInSideExtra=Please check and move one to the Commander Section, in case.
|
||||
lblWarnDeckSectionNotAllowedInEditor={0} Section is not allowed in {1}
|
||||
@@ -3001,6 +3003,7 @@ lblCardImportWarning=\nWarning: The deck {0} will be renamed as {1}.
|
||||
lblConfirmCreateNewDeck=You are about to create a new deck {0}. {1}\n\nWould you like to proceed?\n\n Note: \
|
||||
Please remember to click on the "Save" button in the Deck Editor to add the new deck to the Catalog!
|
||||
lblNewDeckWarning=\nWarning: Any unsaved changes to the current deck {0} will be lost.
|
||||
lblConfirmReplaceDeck=This will replace the contents of the current deck ({0}) with the imported cards.\n\nWould you like to proceed?
|
||||
lblImportCardsDialogTitle=Import cards in the Current Deck
|
||||
lblNewDeckDialogTitle=Create a New Deck
|
||||
#FNetOverlay.java
|
||||
|
||||
@@ -2847,6 +2847,7 @@ lblDecklistTitle=Decklist
|
||||
lblSummaryStats=Summary Statistics
|
||||
lblDeckSection=Section
|
||||
lblNewDeckCheckbox=Create a New Deck
|
||||
lblReplaceDeckCheckbox=Replace Current Deck
|
||||
lblImportCardsCmd=Import Cards
|
||||
lblCreateNewCmd=New Deck
|
||||
lblErrNotAllowedCard=Set not allowed in {0}
|
||||
@@ -2854,6 +2855,7 @@ lblWarnLimitedCard={0} in {1}
|
||||
lblErrCardEditionDate=Set not compliant with Release Date option
|
||||
lblErrUnsupportedCard=Not allowed in {0}
|
||||
lblWarnUnknownCardMsg=Unknown Card or Unsupported in Forge
|
||||
lblWarnNotInInventory=Card not found in inventory
|
||||
lblWarnTooManyCommanders=Current {0} Section contains {1} potential Commander Cards: {2}
|
||||
lblWarnCommandersInSideExtra=Please check and move one to the Commander Section, in case.
|
||||
lblWarnDeckSectionNotAllowedInEditor={0} Section is not allowed in {1}
|
||||
@@ -2950,6 +2952,7 @@ lblCardImportWarning=\nWarning: The deck {0} will be renamed as {1}.
|
||||
lblConfirmCreateNewDeck=You are about to create a new deck {0}. {1}\n\nWould you like to proceed?\n\n Note: \
|
||||
Please remember to click on the "Save" button in the Deck Editor to add the new deck to the Catalog!
|
||||
lblNewDeckWarning=\nWarning: Any unsaved changes to the current deck {0} will be lost.
|
||||
lblConfirmReplaceDeck=This will replace the contents of the current deck ({0}) with the imported cards.\n\nWould you like to proceed?
|
||||
lblImportCardsDialogTitle=Import cards in the Current Deck
|
||||
lblNewDeckDialogTitle=Create a New Deck
|
||||
#FNetOverlay.java
|
||||
|
||||
@@ -2840,6 +2840,7 @@ lblDecklistTitle=Liste de deck
|
||||
lblSummaryStats=Statistiques récapitulatives
|
||||
lblDeckSection=Section
|
||||
lblNewDeckCheckbox=Créer un nouveau deck
|
||||
lblReplaceDeckCheckbox=Replace Current Deck
|
||||
lblImportCardsCmd=Importer des cartes
|
||||
lblCreateNewCmd=Nouveau Deck
|
||||
lblErrNotAllowedCard=Définir non autorisé dans {0}
|
||||
@@ -2847,6 +2848,7 @@ lblWarnLimitedCard={0} dans {1}
|
||||
lblErrCardEditionDate=Set non conforme avec l'option de date de sortie
|
||||
lblErrUnsupportedCard=Non autorisé dans {0}
|
||||
lblWarnUnknownCardMsg=Carte inconnue ou non prise en charge dans Forge
|
||||
lblWarnNotInInventory=Card not found in inventory
|
||||
lblWarnTooManyCommanders=La section {0} actuelle contient {1} cartes de commandant potentielles : {2}
|
||||
lblWarnCommandersInSideExtra=Veuillez vérifier et en déplacer un vers la section Commandant, au cas où.
|
||||
lblWarnDeckSectionNotAllowedInEditor={0} La section n'est pas autorisée dans {1}
|
||||
@@ -2944,6 +2946,7 @@ lblCardImportWarning=\nAttention : Le deck {0} sera renommé en {1}.
|
||||
lblConfirmCreateNewDeck=Vous êtes sur le point de créer un nouveau deck {0}. {1}\n\nVoulez-vous continuer ?\n\n Remarque : \
|
||||
N'oubliez pas de cliquer sur le bouton "Enregistrer" dans l'éditeur de deck pour ajouter le nouveau deck au catalogue !
|
||||
lblNewDeckWarning=\nAttention : Toute modification non enregistrée dans le deck actuel {0} sera perdue.
|
||||
lblConfirmReplaceDeck=This will replace the contents of the current deck ({0}) with the imported cards.\n\nWould you like to proceed?
|
||||
lblImportCardsDialogTitle=Importer des cartes dans le Deck actuel
|
||||
lblNewDeckDialogTitle=Créer un nouveau deck
|
||||
#FNetOverlay.java
|
||||
|
||||
@@ -2836,6 +2836,7 @@ lblDecklistTitle=Lista delle Carte da Importare
|
||||
lblSummaryStats=Statistiche Generali
|
||||
lblDeckSection=Sezione
|
||||
lblNewDeckCheckbox=Crea un nuovo mazzo
|
||||
lblReplaceDeckCheckbox=Replace Current Deck
|
||||
lblImportCardsCmd=Importa le carte
|
||||
lblCreateNewCmd=Nuovo mazzo
|
||||
lblErrNotAllowedCard=Edizione non permessa in {0}
|
||||
@@ -2843,6 +2844,7 @@ lblWarnLimitedCard={0} in {1}
|
||||
lblErrCardEditionDate=Edizione non valida secondo l'opzione sulla data di pubblicazione selezionata
|
||||
lblErrUnsupportedCard=Non Permesso in {0}
|
||||
lblWarnUnknownCardMsg=Carta Sconosciuta, o non supportata in Forge
|
||||
lblWarnNotInInventory=Card not found in inventory
|
||||
lblWarnTooManyCommanders=La Sezione {0} contiene {1} potenziali carte Commander: {2}
|
||||
lblWarnCommandersInSideExtra=Per favore, controlla e nel caso spostane una nella sezione Commander.
|
||||
lblWarnDeckSectionNotAllowedInEditor={0} Sezione non è permessa in {1}
|
||||
@@ -2942,6 +2944,7 @@ lblCardImportWarning=\nAttenzione: Il mazzo {0} sarà rinominato come {1}.
|
||||
lblConfirmCreateNewDeck=Si sta per creare un nuovo mazzo {0}. {1}\n\nSi desidera procedere?\n\n Nota: \
|
||||
Non dimenticare di premere il tasto "Salva" una volta importate le carte per aggiungere il nuovo mazzo al catalogo!
|
||||
lblNewDeckWarning=\nAttenzione: Qualsiasi modifica non salvata al mazzo corrente {0} sarà persa.
|
||||
lblConfirmReplaceDeck=This will replace the contents of the current deck ({0}) with the imported cards.\n\nWould you like to proceed?
|
||||
lblImportCardsDialogTitle=Importa le carte nel mazzo corrente
|
||||
lblNewDeckDialogTitle=Crea un nuovo mazzo
|
||||
#FNetOverlay.java
|
||||
|
||||
@@ -2835,6 +2835,7 @@ lblDecklistTitle=Decklist
|
||||
lblSummaryStats=Summary Statistics
|
||||
lblDeckSection=Section
|
||||
lblNewDeckCheckbox=Create a New Deck
|
||||
lblReplaceDeckCheckbox=Replace Current Deck
|
||||
lblImportCardsCmd=Import Cards
|
||||
lblCreateNewCmd=New Deck
|
||||
lblErrNotAllowedCard=Set not allowed in {0}
|
||||
@@ -2842,6 +2843,7 @@ lblWarnLimitedCard={0} in {1}
|
||||
lblErrCardEditionDate=Set not compliant with Release Date option
|
||||
lblErrUnsupportedCard=Not allowed in {0}
|
||||
lblWarnUnknownCardMsg=Unknown Card or Unsupported in Forge
|
||||
lblWarnNotInInventory=Card not found in inventory
|
||||
lblWarnTooManyCommanders=Current {0} Section contains {1} potential Commander Cards: {2}
|
||||
lblWarnCommandersInSideExtra=Please check and move one to the Commander Section, in case.
|
||||
lblWarnDeckSectionNotAllowedInEditor={0} Section is not allowed in {1}
|
||||
@@ -2938,6 +2940,7 @@ lblCardImportWarning=\nWarning: The deck {0} will be renamed as {1}.
|
||||
lblConfirmCreateNewDeck=You are about to create a new deck {0}. {1}\n\nWould you like to proceed?\n\n Note: \
|
||||
Please remember to click on the "Save" button in the Deck Editor to add the new deck to the Catalog!
|
||||
lblNewDeckWarning=\nWarning: Any unsaved changes to the current deck {0} will be lost.
|
||||
lblConfirmReplaceDeck=This will replace the contents of the current deck ({0}) with the imported cards.\n\nWould you like to proceed?
|
||||
lblImportCardsDialogTitle=Import cards in the Current Deck
|
||||
lblNewDeckDialogTitle=Create a New Deck
|
||||
#FNetOverlay.java
|
||||
|
||||
@@ -2917,6 +2917,7 @@ lblDecklistTitle=Lista de decks
|
||||
lblSummaryStats=Estatísticas Resumidas
|
||||
lblDeckSection=Seção
|
||||
lblNewDeckCheckbox=Criar um Novo deck
|
||||
lblReplaceDeckCheckbox=Replace Current Deck
|
||||
lblImportCardsCmd=Importar Cartas
|
||||
lblCreateNewCmd=Novo Deck
|
||||
lblErrNotAllowedCard=Coleção não permitida em {0}
|
||||
@@ -2924,6 +2925,7 @@ lblWarnLimitedCard={0} em {1}
|
||||
lblErrCardEditionDate=Coleção não compatível com a opção de Data de Lançamento
|
||||
lblErrUnsupportedCard=Não permitido em {0}
|
||||
lblWarnUnknownCardMsg=Carta desconhecida ou não suportada no Forge
|
||||
lblWarnNotInInventory=Card not found in inventory
|
||||
lblWarnTooManyCommanders=Seção {0} Atual contém {1} Cartas de Comandante em potencial\: {2}
|
||||
lblWarnCommandersInSideExtra=Verifique e mova um para a seção do Comandante.
|
||||
lblWarnDeckSectionNotAllowedInEditor=Seção {0} não é permitida em {1}
|
||||
@@ -3012,6 +3014,7 @@ Deseja prosseguir?\n\
|
||||
Nota\: Por favor, lembre-se de clicar no botão "Salvar" no Editor do Deck para adicioná-lo ao Catálogo\!
|
||||
lblNewDeckWarning=\n\
|
||||
Aviso\: Qualquer alteração não salva no deck atual {0} será perdida.
|
||||
lblConfirmReplaceDeck=This will replace the contents of the current deck ({0}) with the imported cards.\n\nWould you like to proceed?
|
||||
lblImportCardsDialogTitle=Importar cartas no Deck Atual
|
||||
lblNewDeckDialogTitle=Criar um Novo deck
|
||||
#FNetOverlay.java
|
||||
|
||||
@@ -2844,6 +2844,7 @@ lblDecklistTitle=套牌列表
|
||||
lblSummaryStats=统计摘要
|
||||
lblDeckSection=部分
|
||||
lblNewDeckCheckbox=创建一个新套牌
|
||||
lblReplaceDeckCheckbox=Replace Current Deck
|
||||
lblImportCardsCmd=导入牌张
|
||||
lblCreateNewCmd=新建套牌
|
||||
lblErrNotAllowedCard=系列{0}不被允许
|
||||
@@ -2851,6 +2852,7 @@ lblWarnLimitedCard={0}中的{1}
|
||||
lblErrCardEditionDate=不符合上市日期选项
|
||||
lblErrUnsupportedCard={0}不被允许
|
||||
lblWarnUnknownCardMsg=未知的牌张或未被forge支持的牌张
|
||||
lblWarnNotInInventory=Card not found in inventory
|
||||
lblWarnTooManyCommanders=现在{0}部分包含{1}张潜在的指挥官牌张: {2}
|
||||
lblWarnCommandersInSideExtra=如果确实是指挥官,请进行进行检查并将其中的一张移动到指挥官区。
|
||||
lblWarnDeckSectionNotAllowedInEditor={0}部分中的{1}不被允许
|
||||
@@ -2928,6 +2930,7 @@ lblCardImportWarning=\n警告:套牌{0}将被重命名为{1}。
|
||||
lblConfirmCreateNewDeck=你即将创建一个新套牌{0}。{1}\n\n你想要继续吗?\n\n 注意:请记得点击套牌编辑器中的\"保存按钮\"以\
|
||||
将新建的套牌保存到目录中!
|
||||
lblNewDeckWarning=\n警告:对于当前套牌{0}的任何未保存更改丢将被丢弃。
|
||||
lblConfirmReplaceDeck=This will replace the contents of the current deck ({0}) with the imported cards.\n\nWould you like to proceed?
|
||||
lblImportCardsDialogTitle=将牌张导入到当前套牌
|
||||
lblNewDeckDialogTitle=创建一个新套牌
|
||||
#FNetOverlay.java
|
||||
|
||||
@@ -13,15 +13,24 @@ import forge.gui.util.SOptionPane;
|
||||
import forge.item.PaperCard;
|
||||
import forge.localinstance.properties.ForgePreferences;
|
||||
import forge.model.FModel;
|
||||
import forge.util.ItemPool;
|
||||
import forge.util.Localizer;
|
||||
import forge.util.StreamUtil;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
|
||||
import java.text.DateFormatSymbols;
|
||||
import java.util.*;
|
||||
import java.util.function.Function;
|
||||
|
||||
public class DeckImportController {
|
||||
private boolean createNewDeck;
|
||||
public enum ImportBehavior {
|
||||
MERGE,
|
||||
CREATE_NEW,
|
||||
REPLACE_CURRENT
|
||||
}
|
||||
|
||||
private ImportBehavior importBehavior;
|
||||
// Date filter
|
||||
private final ICheckBox dateTimeCheck;
|
||||
private final IComboBox<String> monthDropdown;
|
||||
@@ -30,7 +39,7 @@ public class DeckImportController {
|
||||
private CardDb.CardArtPreference artPreference;
|
||||
private boolean smartCardArt;
|
||||
// Block Preference Filter
|
||||
private boolean inlcludeBnRInDeck = false;
|
||||
private boolean includeBnRInDeck = false;
|
||||
|
||||
private final List<Token> tokens = new ArrayList<>();
|
||||
private final Map<PaperCard, Token> cardsInTokens = new HashMap<>();
|
||||
@@ -38,7 +47,14 @@ public class DeckImportController {
|
||||
private Deck currentDeckInEditor = null;
|
||||
private DeckFormat currentDeckFormat;
|
||||
private GameFormat currentGameFormat;
|
||||
private GameType currentGameType;
|
||||
private final List<DeckSection> allowedSections = new ArrayList<>();
|
||||
private ItemPool<PaperCard> playerInventory;
|
||||
/**
|
||||
* If a free card is missing from a player's inventory (e.g. a basic land), it gets run through this function, which
|
||||
* can handle creation of a usable print.
|
||||
*/
|
||||
private Function<PaperCard, PaperCard> freePrintSupplier;
|
||||
|
||||
public DeckImportController(ICheckBox dateTimeCheck0,
|
||||
IComboBox<String> monthDropdown0, IComboBox<Integer> yearDropdown0,
|
||||
@@ -54,13 +70,14 @@ public class DeckImportController {
|
||||
*/
|
||||
this.currentDeckNotEmpty = currentDeckNotEmpty;
|
||||
// this option will control the "new deck" action controlled by UI widget
|
||||
createNewDeck = false;
|
||||
this.importBehavior = ImportBehavior.MERGE;
|
||||
|
||||
// Init default parameters
|
||||
this.artPreference = StaticData.instance().getCardArtPreference(); // default
|
||||
this.smartCardArt = StaticData.instance().isEnabledCardArtSmartSelection();
|
||||
this.currentDeckFormat = null;
|
||||
this.currentGameFormat = null;
|
||||
this.currentGameType = null;
|
||||
fillDateDropdowns();
|
||||
}
|
||||
|
||||
@@ -68,13 +85,23 @@ public class DeckImportController {
|
||||
if (gameType == null){
|
||||
this.currentGameFormat = null;
|
||||
this.currentDeckFormat = null;
|
||||
this.currentGameType = null;
|
||||
} else {
|
||||
// get the game format with the same name of current game type (if any)
|
||||
this.currentDeckFormat = gameType.getDeckFormat();
|
||||
this.currentGameFormat = FModel.getFormats().get(gameType.name());
|
||||
this.currentGameType = gameType;
|
||||
}
|
||||
}
|
||||
|
||||
public void setPlayerInventory(ItemPool<PaperCard> inventory) {
|
||||
this.playerInventory = inventory;
|
||||
}
|
||||
|
||||
public void setFreePrintConverter(Function<PaperCard, PaperCard> freePrintSupplier) {
|
||||
this.freePrintSupplier = freePrintSupplier;
|
||||
}
|
||||
|
||||
public void setCurrentDeckInEditor(Deck deckInEditor){
|
||||
this.currentDeckInEditor = deckInEditor;
|
||||
}
|
||||
@@ -105,11 +132,13 @@ public class DeckImportController {
|
||||
return this.smartCardArt;
|
||||
}
|
||||
|
||||
public void setCreateNewDeck(boolean createNewDeck){
|
||||
this.createNewDeck = createNewDeck;
|
||||
public void setImportBehavior(ImportBehavior importBehavior) {
|
||||
this.importBehavior = importBehavior;
|
||||
}
|
||||
|
||||
public boolean getCreateNewDeck() { return this.createNewDeck; }
|
||||
public ImportBehavior getImportBehavior() {
|
||||
return importBehavior;
|
||||
}
|
||||
|
||||
private void fillDateDropdowns() {
|
||||
DateFormatSymbols dfs = new DateFormatSymbols();
|
||||
@@ -159,10 +188,10 @@ public class DeckImportController {
|
||||
}
|
||||
|
||||
public void importBannedAndRestrictedCards(boolean includeBannedAndRestricted){
|
||||
this.inlcludeBnRInDeck = includeBannedAndRestricted;
|
||||
this.includeBnRInDeck = includeBannedAndRestricted;
|
||||
}
|
||||
|
||||
public boolean importBannedAndRestrictedCards(){ return this.inlcludeBnRInDeck; }
|
||||
public boolean importBannedAndRestrictedCards(){ return this.includeBnRInDeck; }
|
||||
|
||||
public List<Token> parseInput(String input) {
|
||||
tokens.clear();
|
||||
@@ -186,7 +215,7 @@ public class DeckImportController {
|
||||
if (!this.allowedSections.isEmpty())
|
||||
recognizer.setAllowedDeckSections(this.allowedSections);
|
||||
// Banned and Restricted Card Policy
|
||||
if (this.inlcludeBnRInDeck)
|
||||
if (this.includeBnRInDeck)
|
||||
recognizer.forceImportBannedAndRestrictedCards();
|
||||
|
||||
String[] lines = input.split("\n");
|
||||
@@ -196,8 +225,13 @@ public class DeckImportController {
|
||||
|
||||
if (this.currentGameFormatAllowsCommander()) {
|
||||
List<Pair<Integer, Token>> commanderTokens = getTokensInSection(DeckSection.Commander);
|
||||
if (commanderTokens.isEmpty()) // Check commanders in Sideboard only if the commander section is empty
|
||||
checkAndFixCommanderIn(DeckSection.Sideboard);
|
||||
if (commanderTokens.isEmpty()) {
|
||||
// Check commanders in Sideboard only if the commander section is empty
|
||||
if(!getTokensInSection(DeckSection.Sideboard).isEmpty())
|
||||
checkAndFixCommanderIn(DeckSection.Sideboard);
|
||||
else
|
||||
checkAndFixCommanderIn(DeckSection.Main);
|
||||
}
|
||||
checkAndFixCommanderIn(DeckSection.Commander);
|
||||
}
|
||||
|
||||
@@ -309,7 +343,7 @@ public class DeckImportController {
|
||||
}
|
||||
|
||||
public boolean currentGameFormatAllowsCommander(){
|
||||
return this.allowedSections.contains(DeckSection.Commander);
|
||||
return this.allowedSections.contains(DeckSection.Commander) || this.currentGameType == GameType.PlanarConquest;
|
||||
}
|
||||
|
||||
public List<Token> optimiseCardArtInTokens(){
|
||||
@@ -332,13 +366,8 @@ public class DeckImportController {
|
||||
else
|
||||
refTokenMap = tokensPerSectionWithSet;
|
||||
|
||||
List<Token> tokensInSection = refTokenMap.getOrDefault(tokenSection, null);
|
||||
if (tokensInSection == null) {
|
||||
tokensInSection = new ArrayList<>();
|
||||
tokensInSection.add(token);
|
||||
refTokenMap.put(tokenSection, tokensInSection);
|
||||
} else
|
||||
tokensInSection.add(token);
|
||||
List<Token> tokensInSection = refTokenMap.computeIfAbsent(tokenSection, e -> new ArrayList<>());
|
||||
tokensInSection.add(token);
|
||||
}
|
||||
|
||||
if (tokensPerSectionWithNoSet.isEmpty())
|
||||
@@ -356,7 +385,7 @@ public class DeckImportController {
|
||||
|
||||
Map<DeckSection, CardPool> referencePoolPerSection = new HashMap<>();
|
||||
|
||||
if (this.currentDeckNotEmpty && !this.createNewDeck && this.currentDeckInEditor != null){
|
||||
if (this.currentDeckNotEmpty && this.importBehavior == ImportBehavior.MERGE && this.currentDeckInEditor != null){
|
||||
// We will always consider ONLY sections for cards needing art optimisation
|
||||
for (DeckSection section : tokensPerSectionWithNoSet.keySet()){
|
||||
CardPool cardsInDeck = this.currentDeckInEditor.get(section);
|
||||
@@ -436,6 +465,100 @@ public class DeckImportController {
|
||||
return tokens;
|
||||
}
|
||||
|
||||
public List<Token> constrainTokensToInventory() {
|
||||
if(this.playerInventory == null)
|
||||
return tokens;
|
||||
CardPool availableInventory = new CardPool(this.playerInventory);
|
||||
//Map of tokens to the things we're gonna replace them with.
|
||||
Map<Token, List<Token>> tokenReplacers = new LinkedHashMap<>();
|
||||
//If we're adding to our existing deck, ensure we aren't counting the cards already in it.
|
||||
if(this.importBehavior == ImportBehavior.MERGE && this.currentDeckInEditor != null)
|
||||
availableInventory.removeAll(this.currentDeckInEditor.getAllCardsInASinglePool(true, true));
|
||||
if(this.currentGameType == GameType.PlanarConquest && currentDeckInEditor != null)
|
||||
availableInventory.removeAllFlat(this.currentDeckInEditor.getCommanders());
|
||||
//Step 1: For each token, if it's asking for more copies of a print than we can supply, split the difference out
|
||||
//into a token that's indifferent to the edition. Reduce available inventory accordingly.
|
||||
for (Token token : this.tokens) {
|
||||
if (!token.isCardToken())
|
||||
continue;
|
||||
PaperCard card = token.getCard();
|
||||
int requestedAmount = token.getQuantity();
|
||||
if (card == null)
|
||||
continue;
|
||||
if (token.cardRequestHasNoCode()) {
|
||||
List<Token> list = new ArrayList<>();
|
||||
tokenReplacers.put(token, list);
|
||||
continue;
|
||||
}
|
||||
int available = availableInventory.count(card);
|
||||
if (available <= 0) {
|
||||
List<Token> list = new ArrayList<>();
|
||||
tokenReplacers.put(token, list);
|
||||
continue;
|
||||
}
|
||||
int numTaken = Math.min(requestedAmount, available);
|
||||
availableInventory.remove(card, numTaken);
|
||||
if (available >= requestedAmount)
|
||||
continue;
|
||||
|
||||
List<Token> list = new ArrayList<>();
|
||||
list.add(Token.LegalCard(card, numTaken, token.getTokenSection(), true));
|
||||
tokenReplacers.put(token, list);
|
||||
}
|
||||
if(tokenReplacers.isEmpty())
|
||||
return tokens; //We have every card that was requested.
|
||||
//Step 2: Try to find alternative prints for the ones that do not request an edition.
|
||||
int capacity = tokens.size();
|
||||
for(Map.Entry<Token, List<Token>> tokenReplacer : tokenReplacers.entrySet()) {
|
||||
Token token = tokenReplacer.getKey();
|
||||
DeckSection tokenSection = token.getTokenSection();
|
||||
List<Token> replacementList = tokenReplacer.getValue();
|
||||
PaperCard card = token.getCard();
|
||||
String cardName = card.getName();
|
||||
CardPool substitutes = availableInventory.getFilteredPool(c -> c.getName().equals(cardName));
|
||||
List<Map.Entry<PaperCard, Integer>> sortedSubstitutes = StreamUtil.stream(substitutes).sorted(Comparator.comparingInt(Map.Entry::getValue)).toList();
|
||||
int neededQuantity = token.getQuantity();
|
||||
for(Token found : replacementList) {
|
||||
//If there's an item in the replacement list already it means we've already found some of the needed copies.
|
||||
neededQuantity -= found.getQuantity();
|
||||
}
|
||||
for(int i = 0; i < sortedSubstitutes.size() && neededQuantity > 0; i++) {
|
||||
Map.Entry<PaperCard, Integer> item = sortedSubstitutes.get(i);
|
||||
PaperCard replacement = item.getKey();
|
||||
int toMove = Math.min(neededQuantity, item.getValue());
|
||||
replacementList.add(Token.LegalCard(replacement, toMove, tokenSection, true));
|
||||
availableInventory.remove(replacement, toMove);
|
||||
neededQuantity -= toMove;
|
||||
capacity++;
|
||||
}
|
||||
if(neededQuantity > 0) {
|
||||
PaperCard freePrint = getInfiniteSupplyPrinting(card);
|
||||
if(freePrint != null)
|
||||
replacementList.add(Token.NotInInventoryFree(freePrint, neededQuantity, tokenSection));
|
||||
else
|
||||
replacementList.add(Token.NotInInventory(card, neededQuantity, tokenSection));
|
||||
capacity++;
|
||||
}
|
||||
}
|
||||
//Step 3: Apply the replacement list.
|
||||
List<Token> newList = new ArrayList<>(capacity);
|
||||
for(Token t : this.tokens) {
|
||||
if(tokenReplacers.containsKey(t))
|
||||
newList.addAll(tokenReplacers.get(t));
|
||||
else
|
||||
newList.add(t);
|
||||
}
|
||||
this.tokens.clear();
|
||||
this.tokens.addAll(newList);
|
||||
return tokens;
|
||||
}
|
||||
|
||||
private PaperCard getInfiniteSupplyPrinting(PaperCard card) {
|
||||
if(this.freePrintSupplier == null)
|
||||
return null;
|
||||
return freePrintSupplier.apply(card);
|
||||
}
|
||||
|
||||
private int countTokens(List<Token> tokensInSection){
|
||||
if (tokensInSection == null || tokensInSection.isEmpty())
|
||||
return 0;
|
||||
@@ -487,27 +610,31 @@ public class DeckImportController {
|
||||
if (tokens.isEmpty()) { return null; }
|
||||
|
||||
String deckName = "";
|
||||
if (currentDeckName != null && currentDeckName.trim().length() > 0)
|
||||
if (currentDeckName != null && !currentDeckName.trim().isEmpty())
|
||||
deckName = String.format("\"%s\"", currentDeckName.trim());
|
||||
|
||||
String tokenDeckName = getTokenDeckNameIfAny();
|
||||
if (tokenDeckName.length() > 0)
|
||||
if (!tokenDeckName.isEmpty())
|
||||
tokenDeckName = String.format("\"%s\"", tokenDeckName);
|
||||
|
||||
if (createNewDeck){
|
||||
String extraWarning = currentDeckNotEmpty ? localizer.getMessage("lblNewDeckWarning", deckName) : "";
|
||||
final String warning = localizer.getMessage("lblConfirmCreateNewDeck", tokenDeckName, extraWarning);
|
||||
if (!SOptionPane.showConfirmDialog(warning, localizer.getMessage("lblNewDeckDialogTitle"),
|
||||
localizer.getMessage("lblYes"), localizer.getMessage("lblNo"))) {
|
||||
return null;
|
||||
if(this.currentDeckNotEmpty) {
|
||||
final String warning;
|
||||
final String title;
|
||||
if (this.importBehavior == ImportBehavior.CREATE_NEW) {
|
||||
String extraWarning = localizer.getMessage("lblNewDeckWarning", deckName);
|
||||
warning = localizer.getMessage("lblConfirmCreateNewDeck", tokenDeckName, extraWarning);
|
||||
title = localizer.getMessage("lblNewDeckDialogTitle");
|
||||
} else if (this.importBehavior == ImportBehavior.MERGE){
|
||||
String extraWarning = (!tokenDeckName.isEmpty() && !tokenDeckName.equals(deckName)) ?
|
||||
localizer.getMessage("lblCardImportWarning", deckName, tokenDeckName) : "";
|
||||
warning = localizer.getMessage("lblConfirmCardImport", deckName, extraWarning);
|
||||
title = localizer.getMessage("lblImportCardsDialogTitle");
|
||||
}
|
||||
}
|
||||
else if (this.currentDeckNotEmpty){
|
||||
String extraWarning = (tokenDeckName.length() > 0 && !tokenDeckName.equals(deckName)) ?
|
||||
localizer.getMessage("lblCardImportWarning", deckName, tokenDeckName) : "";
|
||||
final String warning = localizer.getMessage("lblConfirmCardImport", deckName, extraWarning);
|
||||
if (!SOptionPane.showConfirmDialog(warning,
|
||||
localizer.getMessage("lblImportCardsDialogTitle"),
|
||||
else {
|
||||
warning = localizer.getMessage("lblConfirmReplaceDeck", deckName);
|
||||
title = localizer.getMessage("lblNewDeckDialogTitle");
|
||||
}
|
||||
if (!SOptionPane.showConfirmDialog(warning, title,
|
||||
localizer.getMessage("lblYes"), localizer.getMessage("lblNo")))
|
||||
return null;
|
||||
}
|
||||
@@ -516,7 +643,7 @@ public class DeckImportController {
|
||||
final TokenType type = t.getType();
|
||||
// only Deck Name, legal card and limited card tokens will be analysed!
|
||||
if (!t.isTokenForDeck() ||
|
||||
(type == TokenType.LIMITED_CARD && !this.inlcludeBnRInDeck))
|
||||
(type == TokenType.LIMITED_CARD && !this.includeBnRInDeck))
|
||||
continue; // SKIP token
|
||||
|
||||
if (type == TokenType.DECK_NAME) {
|
||||
@@ -547,4 +674,66 @@ public class DeckImportController {
|
||||
}
|
||||
return ""; // no deck name
|
||||
}
|
||||
|
||||
public String getTokenMessage(DeckRecognizer.Token token) {
|
||||
return switch (token.getType()) {
|
||||
case LEGAL_CARD, LIMITED_CARD, CARD_FROM_NOT_ALLOWED_SET, CARD_FROM_INVALID_SET,
|
||||
CARD_NOT_IN_INVENTORY, FREE_CARD_NOT_IN_INVENTORY ->
|
||||
String.format("%s x %s %s", token.getQuantity(), token.getText(), getTokenFoilLabel(token));
|
||||
// Card Warning Msgs
|
||||
case UNKNOWN_CARD, UNSUPPORTED_CARD ->
|
||||
token.getQuantity() > 0 ? String.format("%s x %s", token.getQuantity(), token.getText())
|
||||
: token.getText();
|
||||
case UNSUPPORTED_DECK_SECTION ->
|
||||
String.format("%s: %s", Localizer.getInstance().getMessage("lblWarningMsgPrefix"),
|
||||
Localizer.getInstance()
|
||||
.getMessage("lblWarnDeckSectionNotAllowedInEditor", token.getText(),
|
||||
this.currentGameType.name()));
|
||||
|
||||
// Special Case of Card moved into another section (e.g. Commander from Sideboard)
|
||||
case WARNING_MESSAGE -> String.format("%s: %s", Localizer.getInstance()
|
||||
.getMessage("lblWarningMsgPrefix"), token.getText());
|
||||
|
||||
// Placeholders
|
||||
case DECK_SECTION_NAME -> String.format("%s: %s", Localizer.getInstance().getMessage("lblDeckSection"),
|
||||
token.getText());
|
||||
case CARD_RARITY -> String.format("%s: %s", Localizer.getInstance().getMessage("lblRarity"),
|
||||
token.getText());
|
||||
case CARD_TYPE, CARD_CMC, MANA_COLOUR, COMMENT, UNKNOWN_TEXT -> token.getText();
|
||||
case DECK_NAME -> String.format("%s: %s", Localizer.getInstance().getMessage("lblDeckName"),
|
||||
token.getText());
|
||||
};
|
||||
}
|
||||
|
||||
public String getTokenStatusMessage(DeckRecognizer.Token token) {
|
||||
if (token == null)
|
||||
return "";
|
||||
|
||||
final Localizer localizer = Localizer.getInstance();
|
||||
return switch (token.getType()) {
|
||||
case LIMITED_CARD -> String.format("%s: %s", localizer.getMessage("lblWarningMsgPrefix"),
|
||||
localizer.getMessage("lblWarnLimitedCard",
|
||||
StringUtils.capitalize(token.getLimitedCardType().name()), getGameFormatLabel()));
|
||||
case CARD_FROM_NOT_ALLOWED_SET ->
|
||||
localizer.getMessage("lblErrNotAllowedCard", getGameFormatLabel());
|
||||
case CARD_FROM_INVALID_SET -> localizer.getMessage("lblErrCardEditionDate");
|
||||
case UNSUPPORTED_CARD -> localizer.getMessage("lblErrUnsupportedCard", this.currentGameType);
|
||||
case UNKNOWN_CARD -> String.format("%s: %s", localizer.getMessage("lblWarningMsgPrefix"),
|
||||
localizer.getMessage("lblWarnUnknownCardMsg"));
|
||||
case CARD_NOT_IN_INVENTORY -> localizer.getMessage("lblWarnNotInInventory");
|
||||
default -> "";
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
private String getTokenFoilLabel(DeckRecognizer.Token token) {
|
||||
if (!token.isCardToken())
|
||||
return "";
|
||||
final String foilMarker = "- (Foil)";
|
||||
return token.getCard().isFoil() ? foilMarker : "";
|
||||
}
|
||||
|
||||
private String getGameFormatLabel() {
|
||||
return String.format("\"%s\"", this.getCurrentGameFormatName());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -774,7 +774,7 @@ public class DeckProxy implements InventoryItem {
|
||||
|
||||
for (PaperCard c : deck.getAllCardsInASinglePool().toFlatList()) {
|
||||
CardEdition edition = FModel.getMagicDb().getEditions().get(c.getEdition());
|
||||
if (edition == null)
|
||||
if (edition == null || !edition.hasBasicLands())
|
||||
continue;
|
||||
availableEditions.add(edition);
|
||||
}
|
||||
|
||||
@@ -18,15 +18,11 @@
|
||||
package forge.gamemodes.planarconquest;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.*;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import forge.card.CardDb;
|
||||
import forge.gamemodes.planarconquest.ConquestPreferences.CQPref;
|
||||
@@ -199,14 +195,11 @@ public final class ConquestData {
|
||||
}
|
||||
|
||||
public int getAccessiblePlaneCount() {
|
||||
// TODO: Java 8 stream implementation of filtering
|
||||
int i = 0;
|
||||
for (ConquestPlane plane : FModel.getPlanes()) {
|
||||
if (!plane.isUnreachable()) {
|
||||
i++;
|
||||
}
|
||||
}
|
||||
return i;
|
||||
return (int) FModel.getPlanes().stream().filter(Predicate.not(ConquestPlane::isUnreachable)).count();
|
||||
}
|
||||
|
||||
public Set<ConquestPlane> getUnlockedPlanes() {
|
||||
return planeDataMap.values().stream().map(ConquestPlaneData::getLocation).map(ConquestLocation::getPlane).collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
public void unlockPlane(ConquestPlane plane) {
|
||||
@@ -302,7 +295,7 @@ public final class ConquestData {
|
||||
}
|
||||
}
|
||||
|
||||
if (commandersUsingCard.length() > 0) {
|
||||
if (!commandersUsingCard.isEmpty()) {
|
||||
SOptionPane.showMessageDialog(Localizer.getInstance().getMessage("lblCommandersCardCannotBeExiledByCard", CardTranslation.getTranslatedName(card.getName()), commandersUsingCard), title, SOptionPane.INFORMATION_ICON);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -50,6 +50,7 @@ public class ConquestPlane {
|
||||
private FCollection<PaperCard> commanders;
|
||||
private ConquestAwardPool awardPool;
|
||||
private ConquestEvent[] events;
|
||||
private final Set<CardEdition> editions = new HashSet<>();
|
||||
|
||||
private ConquestPlane(String name0, String description0, int regionSize0, boolean unreachable0) {
|
||||
name = name0;
|
||||
@@ -153,6 +154,10 @@ public class ConquestPlane {
|
||||
return planeCards;
|
||||
}
|
||||
|
||||
public Set<CardEdition> getEditions() {
|
||||
return editions;
|
||||
}
|
||||
|
||||
private void ensureRegionsLoaded() {
|
||||
if (regions != null) { return; }
|
||||
|
||||
@@ -193,6 +198,8 @@ public class ConquestPlane {
|
||||
if (edition == null)
|
||||
continue;
|
||||
|
||||
editions.add(edition);
|
||||
|
||||
for (EditionEntry card : edition.getObtainableCards()) {
|
||||
if (bannedCardSet == null || !bannedCardSet.contains(card.name())) {
|
||||
addCard(commonCards.getCard(card.name(), setCode));
|
||||
|
||||
@@ -1,22 +1,16 @@
|
||||
package forge.gamemodes.planarconquest;
|
||||
|
||||
import java.util.EnumSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.*;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Maps;
|
||||
import com.google.common.collect.Sets;
|
||||
|
||||
import forge.card.CardRarity;
|
||||
import forge.card.CardRules;
|
||||
import forge.card.CardType;
|
||||
import forge.card.*;
|
||||
import forge.card.CardType.CoreType;
|
||||
import forge.card.ColorSet;
|
||||
import forge.card.MagicColor;
|
||||
import forge.card.mana.ManaCostShard;
|
||||
import forge.deck.CardPool;
|
||||
import forge.deck.Deck;
|
||||
@@ -143,6 +137,25 @@ public class ConquestUtil {
|
||||
return pool;
|
||||
}
|
||||
|
||||
public static List<CardEdition> getBasicLandSets(Deck currentDeck) {
|
||||
ConquestData model = FModel.getConquest().getModel();
|
||||
List<ConquestPlane> planes = new ArrayList<>(model.getUnlockedPlanes());
|
||||
ConquestPlane currentPlane = model.getCurrentPlane();
|
||||
//Move the current plane to the front.
|
||||
if(currentPlane != null && planes.contains(currentPlane)) {
|
||||
planes.remove(currentPlane);
|
||||
planes.add(0, currentPlane);
|
||||
}
|
||||
//Move editions of cards already in the deck to the front.
|
||||
Map<CardEdition, Integer> editionStats = currentDeck.getAllCardsInASinglePool().getCardEditionStatistics(true);
|
||||
List<CardEdition> out = planes.stream()
|
||||
.<CardEdition>mapMulti((p, c) -> p.getEditions().forEach(c))
|
||||
.filter(CardEdition::hasBasicLands)
|
||||
.sorted(Comparator.comparing(e -> editionStats.getOrDefault(e, 0)))
|
||||
.collect(Collectors.toList());
|
||||
return out;
|
||||
}
|
||||
|
||||
public static ConquestPlane getPlaneByName(String planeName) {
|
||||
for (ConquestPlane plane : FModel.getPlanes()) {
|
||||
if (plane.getName().equals(planeName)) {
|
||||
@@ -189,19 +202,16 @@ public class ConquestUtil {
|
||||
public static int getShardValue(CardRarity rarity, CQPref baseValuePref) {
|
||||
ConquestPreferences prefs = FModel.getConquestPreferences();
|
||||
int baseValue = prefs.getPrefInt(baseValuePref);
|
||||
switch (rarity) {
|
||||
case Common:
|
||||
return baseValue;
|
||||
case Uncommon:
|
||||
return Math.round((float)baseValue * (float)prefs.getPrefInt(CQPref.AETHER_UNCOMMON_MULTIPLIER));
|
||||
case Rare:
|
||||
case Special:
|
||||
return Math.round((float)baseValue * (float)prefs.getPrefInt(CQPref.AETHER_RARE_MULTIPLIER));
|
||||
case MythicRare:
|
||||
return Math.round((float)baseValue * (float)prefs.getPrefInt(CQPref.AETHER_MYTHIC_MULTIPLIER));
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
return switch (rarity) {
|
||||
case Common -> baseValue;
|
||||
case Uncommon ->
|
||||
Math.round((float) baseValue * (float) prefs.getPrefInt(CQPref.AETHER_UNCOMMON_MULTIPLIER));
|
||||
case Rare, Special ->
|
||||
Math.round((float) baseValue * (float) prefs.getPrefInt(CQPref.AETHER_RARE_MULTIPLIER));
|
||||
case MythicRare ->
|
||||
Math.round((float) baseValue * (float) prefs.getPrefInt(CQPref.AETHER_MYTHIC_MULTIPLIER));
|
||||
default -> 0;
|
||||
};
|
||||
}
|
||||
|
||||
public enum AEtherFilter implements IHasSkinProp {
|
||||
|
||||
@@ -19,6 +19,7 @@ package forge.gamemodes.quest;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.eventbus.Subscribe;
|
||||
@@ -620,17 +621,21 @@ public class QuestController {
|
||||
}
|
||||
|
||||
public CardEdition getDefaultLandSet() {
|
||||
List<String> availableEditionCodes = questFormat != null ? questFormat.getAllowedSetCodes() : Lists.newArrayList(FModel.getMagicDb().getEditions().getItemNames());
|
||||
List<CardEdition> availableEditions = new ArrayList<>();
|
||||
|
||||
for (String s : availableEditionCodes) {
|
||||
availableEditions.add(FModel.getMagicDb().getEditions().get(s));
|
||||
}
|
||||
List<CardEdition> availableEditions = getAvailableLandSets();
|
||||
|
||||
CardEdition randomLandSet = CardEdition.Predicates.getRandomSetWithAllBasicLands(availableEditions);
|
||||
return randomLandSet == null ? FModel.getMagicDb().getEditions().get("ZEN") : randomLandSet;
|
||||
}
|
||||
|
||||
public List<CardEdition> getAvailableLandSets() {
|
||||
List<String> availableEditionCodes = questFormat != null ? questFormat.getAllowedSetCodes() : Lists.newArrayList(FModel.getMagicDb().getEditions().getItemNames());
|
||||
CardEdition.Collection editions = FModel.getMagicDb().getEditions();
|
||||
return availableEditionCodes.stream()
|
||||
.map(editions::get)
|
||||
.filter(CardEdition::hasBasicLands)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public String getCurrentDeck() {
|
||||
return model.currentDeck;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user