mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-16 10:48:00 +00:00
Store cards by collectorNumber instead of artIndex; PaperCard flag support (#7240)
* Refactor - Unknown set code to constant * Refactor - Support for multiple initial selections for getChoices * Covert noSell and marked color identities into serializable flags * Fix cards in deck not being converted to newer noSell format * unused imports * Fix NPE * Cleanup card filter * Remove 14-year-old check that shouldn't be possible anymore * CRLF -> LF --------- Co-authored-by: Jetz <Jetz722@gmail.com>
This commit is contained in:
@@ -158,7 +158,7 @@ public class ComputerUtilMana {
|
||||
}
|
||||
|
||||
// Mana abilities on the same card
|
||||
String shardMana = shard.toString().replaceAll("\\{", "").replaceAll("\\}", "");
|
||||
String shardMana = shard.toShortString();
|
||||
|
||||
boolean payWithAb1 = ability1.getManaPart().mana(ability1).contains(shardMana);
|
||||
boolean payWithAb2 = ability2.getManaPart().mana(ability2).contains(shardMana);
|
||||
|
||||
@@ -42,7 +42,8 @@ import java.util.stream.Stream;
|
||||
public final class CardDb implements ICardDatabase, IDeckGenPool {
|
||||
public final static String foilSuffix = "+";
|
||||
public final static char NameSetSeparator = '|';
|
||||
public final static String colorIDPrefix = "#";
|
||||
public final static String FlagPrefix = "#";
|
||||
public static final String FlagSeparator = "\t";
|
||||
private final String exlcudedCardName = "Concentrate";
|
||||
private final String exlcudedCardSet = "DS0";
|
||||
|
||||
@@ -93,19 +94,19 @@ public final class CardDb implements ICardDatabase, IDeckGenPool {
|
||||
public int artIndex;
|
||||
public boolean isFoil;
|
||||
public String collectorNumber;
|
||||
public Set<String> colorID;
|
||||
public Map<String, String> flags;
|
||||
|
||||
private CardRequest(String name, String edition, int artIndex, boolean isFoil, String collectorNumber) {
|
||||
this(name, edition, artIndex, isFoil, collectorNumber, null);
|
||||
}
|
||||
|
||||
private CardRequest(String name, String edition, int artIndex, boolean isFoil, String collectorNumber, Set<String> colorID) {
|
||||
private CardRequest(String name, String edition, int artIndex, boolean isFoil, String collectorNumber, Map<String, String> flags) {
|
||||
cardName = name;
|
||||
this.edition = edition;
|
||||
this.artIndex = artIndex;
|
||||
this.isFoil = isFoil;
|
||||
this.collectorNumber = collectorNumber;
|
||||
this.colorID = colorID;
|
||||
this.flags = flags;
|
||||
}
|
||||
|
||||
public static boolean isFoilCardName(final String cardName){
|
||||
@@ -120,7 +121,8 @@ public final class CardDb implements ICardDatabase, IDeckGenPool {
|
||||
}
|
||||
|
||||
public static String compose(String cardName, String setCode) {
|
||||
setCode = setCode != null ? setCode : "";
|
||||
if(setCode == null || StringUtils.isBlank(setCode) || setCode.equals(CardEdition.UNKNOWN_CODE))
|
||||
setCode = "";
|
||||
cardName = cardName != null ? cardName : "";
|
||||
if (cardName.indexOf(NameSetSeparator) != -1)
|
||||
// If cardName is another RequestString, just get card name and forget about the rest.
|
||||
@@ -134,14 +136,6 @@ public final class CardDb implements ICardDatabase, IDeckGenPool {
|
||||
return requestInfo + NameSetSeparator + artIndex;
|
||||
}
|
||||
|
||||
public static String compose(String cardName, String setCode, int artIndex, Set<String> colorID) {
|
||||
String requestInfo = compose(cardName, setCode);
|
||||
artIndex = Math.max(artIndex, IPaperCard.DEFAULT_ART_INDEX);
|
||||
String cid = colorID == null ? "" : NameSetSeparator +
|
||||
colorID.toString().replace("[", colorIDPrefix).replace(", ", colorIDPrefix).replace("]", "");
|
||||
return requestInfo + NameSetSeparator + artIndex + cid;
|
||||
}
|
||||
|
||||
public static String compose(String cardName, String setCode, String collectorNumber) {
|
||||
String requestInfo = compose(cardName, setCode);
|
||||
// CollectorNumber will be wrapped in square brackets
|
||||
@@ -149,6 +143,34 @@ public final class CardDb implements ICardDatabase, IDeckGenPool {
|
||||
return requestInfo + NameSetSeparator + collectorNumber;
|
||||
}
|
||||
|
||||
public static String compose(String cardName, String setCode, int artIndex, Map<String, String> flags) {
|
||||
String requestInfo = compose(cardName, setCode);
|
||||
artIndex = Math.max(artIndex, IPaperCard.DEFAULT_ART_INDEX);
|
||||
if(flags == null)
|
||||
return requestInfo + NameSetSeparator + artIndex;
|
||||
return requestInfo + NameSetSeparator + artIndex + getFlagSegment(flags);
|
||||
}
|
||||
|
||||
public static String compose(String cardName, String setCode, String collectorNumber, Map<String, String> flags) {
|
||||
String requestInfo = compose(cardName, setCode);
|
||||
collectorNumber = preprocessCollectorNumber(collectorNumber);
|
||||
if(flags == null || flags.isEmpty())
|
||||
return requestInfo + NameSetSeparator + collectorNumber;
|
||||
return requestInfo + NameSetSeparator + collectorNumber + getFlagSegment(flags);
|
||||
}
|
||||
|
||||
public static String compose(PaperCard card) {
|
||||
String name = compose(card.getName(), card.isFoil());
|
||||
return compose(name, card.getEdition(), card.getCollectorNumber(), card.getMarkedFlags().toMap());
|
||||
}
|
||||
|
||||
public static String compose(String cardName, String setCode, int artIndex, String collectorNumber) {
|
||||
String requestInfo = compose(cardName, setCode, artIndex);
|
||||
// CollectorNumber will be wrapped in square brackets
|
||||
collectorNumber = preprocessCollectorNumber(collectorNumber);
|
||||
return requestInfo + NameSetSeparator + collectorNumber;
|
||||
}
|
||||
|
||||
private static String preprocessCollectorNumber(String collectorNumber) {
|
||||
if (collectorNumber == null)
|
||||
return "";
|
||||
@@ -160,19 +182,21 @@ public final class CardDb implements ICardDatabase, IDeckGenPool {
|
||||
return collectorNumber;
|
||||
}
|
||||
|
||||
public static String compose(String cardName, String setCode, int artIndex, String collectorNumber) {
|
||||
String requestInfo = compose(cardName, setCode, artIndex);
|
||||
// CollectorNumber will be wrapped in square brackets
|
||||
collectorNumber = preprocessCollectorNumber(collectorNumber);
|
||||
return requestInfo + NameSetSeparator + collectorNumber;
|
||||
private static String getFlagSegment(Map<String, String> flags) {
|
||||
if(flags == null)
|
||||
return "";
|
||||
String flagText = flags.entrySet().stream()
|
||||
.map(e -> e.getKey() + "=" + e.getValue())
|
||||
.collect(Collectors.joining(FlagSeparator));
|
||||
return NameSetSeparator + FlagPrefix + "{" + flagText + "}";
|
||||
}
|
||||
|
||||
private static boolean isCollectorNumber(String s) {
|
||||
return s.startsWith("[") && s.endsWith("]");
|
||||
}
|
||||
|
||||
private static boolean isColorIDString(String s) {
|
||||
return s.startsWith(colorIDPrefix);
|
||||
private static boolean isFlagSegment(String s) {
|
||||
return s.startsWith(FlagPrefix);
|
||||
}
|
||||
|
||||
private static boolean isArtIndex(String s) {
|
||||
@@ -201,44 +225,36 @@ public final class CardDb implements ICardDatabase, IDeckGenPool {
|
||||
return null;
|
||||
|
||||
String[] info = TextUtil.split(reqInfo, NameSetSeparator);
|
||||
int setPos;
|
||||
int artPos;
|
||||
int cNrPos;
|
||||
int clrPos;
|
||||
if (info.length >= 4) { // name|set|artIndex|[collNr]
|
||||
setPos = isSetCode(info[1]) ? 1 : -1;
|
||||
artPos = isArtIndex(info[2]) ? 2 : -1;
|
||||
cNrPos = isCollectorNumber(info[3]) ? 3 : -1;
|
||||
int pos = cNrPos > 0 ? -1 : 3;
|
||||
clrPos = pos > 0 ? isColorIDString(info[pos]) ? pos : -1 : -1;
|
||||
} else if (info.length == 3) { // name|set|artIndex (or CollNr)
|
||||
setPos = isSetCode(info[1]) ? 1 : -1;
|
||||
artPos = isArtIndex(info[2]) ? 2 : -1;
|
||||
cNrPos = isCollectorNumber(info[2]) ? 2 : -1;
|
||||
int pos = cNrPos > 0 ? -1 : 2;
|
||||
clrPos = pos > 0 ? isColorIDString(info[pos]) ? pos : -1 : -1;
|
||||
} else if (info.length == 2) { // name|set (or artIndex, even if not possible via compose)
|
||||
setPos = isSetCode(info[1]) ? 1 : -1;
|
||||
artPos = isArtIndex(info[1]) ? 1 : -1;
|
||||
cNrPos = -1;
|
||||
clrPos = -1;
|
||||
} else {
|
||||
setPos = -1;
|
||||
artPos = -1;
|
||||
cNrPos = -1;
|
||||
clrPos = -1;
|
||||
}
|
||||
int index = 1;
|
||||
String cardName = info[0];
|
||||
boolean isFoil = false;
|
||||
int artIndex = IPaperCard.NO_ART_INDEX;
|
||||
String setCode = null;
|
||||
String collectorNumber = IPaperCard.NO_COLLECTOR_NUMBER;
|
||||
Map<String, String> flags = null;
|
||||
if (isFoilCardName(cardName)) {
|
||||
cardName = cardName.substring(0, cardName.length() - foilSuffix.length());
|
||||
isFoil = true;
|
||||
}
|
||||
int artIndex = artPos > 0 ? Integer.parseInt(info[artPos]) : IPaperCard.NO_ART_INDEX; // default: no art index
|
||||
String collectorNumber = cNrPos > 0 ? info[cNrPos].substring(1, info[cNrPos].length() - 1) : IPaperCard.NO_COLLECTOR_NUMBER;
|
||||
String setCode = setPos > 0 ? info[setPos] : null;
|
||||
Set<String> colorID = clrPos > 0 ? Arrays.stream(info[clrPos].substring(1).split(colorIDPrefix)).collect(Collectors.toSet()) : null;
|
||||
if (setCode != null && setCode.equals(CardEdition.UNKNOWN.getCode())) { // ???
|
||||
|
||||
if(info.length > index && isSetCode(info[index])) {
|
||||
setCode = info[index];
|
||||
index++;
|
||||
}
|
||||
if(info.length > index && isArtIndex(info[index])) {
|
||||
artIndex = Integer.parseInt(info[index]);
|
||||
index++;
|
||||
}
|
||||
if(info.length > index && isCollectorNumber(info[index])) {
|
||||
collectorNumber = info[index].substring(1, info[index].length() - 1);
|
||||
index++;
|
||||
}
|
||||
if (info.length > index && isFlagSegment(info[index])) {
|
||||
String flagText = info[index].substring(FlagPrefix.length());
|
||||
flags = parseRequestFlags(flagText);
|
||||
}
|
||||
|
||||
if (CardEdition.UNKNOWN_CODE.equals(setCode)) { // ???
|
||||
setCode = null;
|
||||
}
|
||||
if (setCode == null) {
|
||||
@@ -253,7 +269,29 @@ public final class CardDb implements ICardDatabase, IDeckGenPool {
|
||||
// finally, check whether any between artIndex and CollectorNumber has been set
|
||||
if (collectorNumber.equals(IPaperCard.NO_COLLECTOR_NUMBER) && artIndex == IPaperCard.NO_ART_INDEX)
|
||||
artIndex = IPaperCard.DEFAULT_ART_INDEX;
|
||||
return new CardRequest(cardName, setCode, artIndex, isFoil, collectorNumber, colorID);
|
||||
return new CardRequest(cardName, setCode, artIndex, isFoil, collectorNumber, flags);
|
||||
}
|
||||
|
||||
private static Map<String, String> parseRequestFlags(String flagText) {
|
||||
flagText = flagText.trim();
|
||||
if(flagText.isEmpty())
|
||||
return null;
|
||||
if(!flagText.startsWith("{")) {
|
||||
//Legacy form for marked colors. They'll be of the form "W#B#R"
|
||||
Map<String, String> flags = new HashMap<>();
|
||||
String normalizedColorString = ColorSet.fromNames(flagText.split(FlagPrefix)).toString();
|
||||
flags.put("markedColors", String.join("", normalizedColorString));
|
||||
return flags;
|
||||
}
|
||||
flagText = flagText.substring(1, flagText.length() - 1); //Trim the braces.
|
||||
//List of flags, a series of "key=value" text broken up by tabs.
|
||||
return Arrays.stream(flagText.split(FlagSeparator))
|
||||
.map(f -> f.split("=", 2))
|
||||
.filter(f -> f.length > 0)
|
||||
.collect(Collectors.toMap(
|
||||
entry -> entry[0],
|
||||
entry -> entry.length > 1 ? entry[1] : "true" //If there's no '=' in the entry, treat it as a boolean flag.
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -406,7 +444,7 @@ public final class CardDb implements ICardDatabase, IDeckGenPool {
|
||||
addCard(new PaperCard(cr, upcomingSet.getCode(), CardRarity.Unknown));
|
||||
} else if (enableUnknownCards && !this.filtered.contains(cr.getName())) {
|
||||
System.err.println("The card " + cr.getName() + " was not assigned to any set. Adding it to UNKNOWN set... to fix see res/editions/ folder. ");
|
||||
addCard(new PaperCard(cr, CardEdition.UNKNOWN.getCode(), CardRarity.Special));
|
||||
addCard(new PaperCard(cr, CardEdition.UNKNOWN_CODE, CardRarity.Special));
|
||||
}
|
||||
} else {
|
||||
System.err.println("The custom card " + cr.getName() + " was not assigned to any set. Adding it to custom USER set, and will try to load custom art from USER edition.");
|
||||
@@ -592,15 +630,8 @@ public final class CardDb implements ICardDatabase, IDeckGenPool {
|
||||
}
|
||||
|
||||
@Override
|
||||
public PaperCard getCard(final String cardName, String setCode, int artIndex, String collectorNumber) {
|
||||
String reqInfo = CardRequest.compose(cardName, setCode, artIndex, collectorNumber);
|
||||
CardRequest request = CardRequest.fromString(reqInfo);
|
||||
return tryGetCard(request);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PaperCard getCard(final String cardName, String setCode, int artIndex, Set<String> colorID) {
|
||||
String reqInfo = CardRequest.compose(cardName, setCode, artIndex, colorID);
|
||||
public PaperCard getCard(final String cardName, String setCode, int artIndex, Map<String, String> flags) {
|
||||
String reqInfo = CardRequest.compose(cardName, setCode, artIndex, flags);
|
||||
CardRequest request = CardRequest.fromString(reqInfo);
|
||||
return tryGetCard(request);
|
||||
}
|
||||
@@ -611,14 +642,17 @@ public final class CardDb implements ICardDatabase, IDeckGenPool {
|
||||
return null;
|
||||
// 1. First off, try using all possible search parameters, to narrow down the actual cards looked for.
|
||||
String reqEditionCode = request.edition;
|
||||
if (reqEditionCode != null && reqEditionCode.length() > 0) {
|
||||
if (reqEditionCode != null && !reqEditionCode.isEmpty()) {
|
||||
// This get is robust even against expansion aliases (e.g. TE and TMP both valid for Tempest) -
|
||||
// MOST of the extensions have two short codes, 141 out of 221 (so far)
|
||||
// ALSO: Set Code are always UpperCase
|
||||
CardEdition edition = editions.get(reqEditionCode.toUpperCase());
|
||||
|
||||
return this.getCardFromSet(request.cardName, edition, request.artIndex,
|
||||
request.collectorNumber, request.isFoil, request.colorID);
|
||||
PaperCard cardFromSet = this.getCardFromSet(request.cardName, edition, request.artIndex, request.collectorNumber, request.isFoil);
|
||||
if(cardFromSet != null && request.flags != null)
|
||||
cardFromSet = cardFromSet.copyWithFlags(request.flags);
|
||||
|
||||
return cardFromSet;
|
||||
}
|
||||
|
||||
// 2. Card lookup in edition with specified filter didn't work.
|
||||
@@ -661,11 +695,6 @@ public final class CardDb implements ICardDatabase, IDeckGenPool {
|
||||
|
||||
@Override
|
||||
public PaperCard getCardFromSet(String cardName, CardEdition edition, int artIndex, String collectorNumber, boolean isFoil) {
|
||||
return getCardFromSet(cardName, edition, artIndex, collectorNumber, isFoil, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PaperCard getCardFromSet(String cardName, CardEdition edition, int artIndex, String collectorNumber, boolean isFoil, Set<String> colorID) {
|
||||
if (edition == null || cardName == null) // preview cards
|
||||
return null; // No cards will be returned
|
||||
|
||||
@@ -674,18 +703,18 @@ public final class CardDb implements ICardDatabase, IDeckGenPool {
|
||||
cardName = cardNameRequest.cardName;
|
||||
isFoil = isFoil || cardNameRequest.isFoil;
|
||||
|
||||
List<PaperCard> candidates = getAllCards(cardName, c -> {
|
||||
boolean artIndexFilter = true;
|
||||
boolean collectorNumberFilter = true;
|
||||
boolean setFilter = c.getEdition().equalsIgnoreCase(edition.getCode()) ||
|
||||
c.getEdition().equalsIgnoreCase(edition.getCode2());
|
||||
if (artIndex > 0)
|
||||
artIndexFilter = (c.getArtIndex() == artIndex);
|
||||
if ((collectorNumber != null) && (collectorNumber.length() > 0)
|
||||
&& !(collectorNumber.equals(IPaperCard.NO_COLLECTOR_NUMBER)))
|
||||
collectorNumberFilter = (c.getCollectorNumber().equals(collectorNumber));
|
||||
return setFilter && artIndexFilter && collectorNumberFilter;
|
||||
});
|
||||
String code1 = edition.getCode(), code2 = edition.getCode2();
|
||||
|
||||
Predicate<PaperCard> filter = (c) -> {
|
||||
String ed = c.getEdition();
|
||||
return ed.equalsIgnoreCase(code1) || ed.equalsIgnoreCase(code2);
|
||||
};
|
||||
if (artIndex > 0)
|
||||
filter = filter.and((c) -> artIndex == c.getArtIndex());
|
||||
if (collectorNumber != null && !collectorNumber.isEmpty() && !collectorNumber.equals(IPaperCard.NO_COLLECTOR_NUMBER))
|
||||
filter = filter.and((c) -> collectorNumber.equals(c.getCollectorNumber()));
|
||||
|
||||
List<PaperCard> candidates = getAllCards(cardName, filter);
|
||||
if (candidates.isEmpty())
|
||||
return null;
|
||||
|
||||
@@ -699,7 +728,7 @@ public final class CardDb implements ICardDatabase, IDeckGenPool {
|
||||
while (!candidate.hasImage() && candidatesIterator.hasNext())
|
||||
candidate = candidatesIterator.next();
|
||||
candidate = candidate.hasImage() ? candidate : firstCandidate;
|
||||
return isFoil ? candidate.getFoiled().getColorIDVersion(colorID) : candidate.getColorIDVersion(colorID);
|
||||
return isFoil ? candidate.getFoiled() : candidate;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -742,11 +771,6 @@ public final class CardDb implements ICardDatabase, IDeckGenPool {
|
||||
return this.tryToGetCardFromEditions(cardInfo, artPreference, artIndex, filter);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PaperCard getCardFromEditions(final String cardInfo, final CardArtPreference artPreference, int artIndex, Set<String> colorID) {
|
||||
return this.tryToGetCardFromEditions(cardInfo, artPreference, artIndex, null, false, null, colorID);
|
||||
}
|
||||
|
||||
/*
|
||||
* ===============================================
|
||||
* 4. SPECIALISED CARD LOOKUP BASED ON
|
||||
@@ -820,12 +844,7 @@ public final class CardDb implements ICardDatabase, IDeckGenPool {
|
||||
}
|
||||
|
||||
private PaperCard tryToGetCardFromEditions(String cardInfo, CardArtPreference artPreference, int artIndex,
|
||||
Date releaseDate, boolean releasedBeforeFlag, Predicate<PaperCard> filter){
|
||||
return this.tryToGetCardFromEditions(cardInfo, artPreference, artIndex, releaseDate, releasedBeforeFlag, filter, null);
|
||||
}
|
||||
|
||||
private PaperCard tryToGetCardFromEditions(String cardInfo, CardArtPreference artPreference, int artIndex,
|
||||
Date releaseDate, boolean releasedBeforeFlag, Predicate<PaperCard> filter, Set<String> colorID){
|
||||
Date releaseDate, boolean releasedBeforeFlag, Predicate<PaperCard> filter) {
|
||||
if (cardInfo == null)
|
||||
return null;
|
||||
final CardRequest cr = CardRequest.fromString(cardInfo);
|
||||
@@ -865,7 +884,7 @@ public final class CardDb implements ICardDatabase, IDeckGenPool {
|
||||
for (PaperCard card : cards) {
|
||||
String setCode = card.getEdition();
|
||||
CardEdition ed;
|
||||
if (setCode.equals(CardEdition.UNKNOWN.getCode()))
|
||||
if (setCode.equals(CardEdition.UNKNOWN_CODE))
|
||||
ed = CardEdition.UNKNOWN;
|
||||
else
|
||||
ed = editions.get(card.getEdition());
|
||||
@@ -906,7 +925,7 @@ public final class CardDb implements ICardDatabase, IDeckGenPool {
|
||||
}
|
||||
candidate = candidate.hasImage() ? candidate : firstCandidate;
|
||||
//If any, we're sure that at least one candidate is always returned despite it having any image
|
||||
return cr.isFoil ? candidate.getFoiled().getColorIDVersion(colorID) : candidate.getColorIDVersion(colorID);
|
||||
return cr.isFoil ? candidate.getFoiled() : candidate;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -1126,29 +1145,6 @@ public final class CardDb implements ICardDatabase, IDeckGenPool {
|
||||
.anyMatch(rarity::equals);
|
||||
}
|
||||
|
||||
public StringBuilder appendCardToStringBuilder(PaperCard card, StringBuilder sb) {
|
||||
final boolean hasBadSetInfo = card.getEdition().equals(CardEdition.UNKNOWN.getCode()) || StringUtils.isBlank(card.getEdition());
|
||||
sb.append(card.getName());
|
||||
if (card.isFoil()) {
|
||||
sb.append(CardDb.foilSuffix);
|
||||
}
|
||||
|
||||
if (!hasBadSetInfo) {
|
||||
int artCount = getArtCount(card.getName(), card.getEdition(), card.getFunctionalVariant());
|
||||
sb.append(CardDb.NameSetSeparator).append(card.getEdition());
|
||||
if (artCount >= IPaperCard.DEFAULT_ART_INDEX) {
|
||||
sb.append(CardDb.NameSetSeparator).append(card.getArtIndex()); // indexes start at 1 to match image file name conventions
|
||||
}
|
||||
if (card.getColorID() != null) {
|
||||
sb.append(CardDb.NameSetSeparator);
|
||||
for (String color : card.getColorID())
|
||||
sb.append(CardDb.colorIDPrefix).append(color);
|
||||
}
|
||||
}
|
||||
|
||||
return sb;
|
||||
}
|
||||
|
||||
public PaperCard createUnsupportedCard(String cardRequest) {
|
||||
CardRequest request = CardRequest.fromString(cardRequest);
|
||||
CardEdition cardEdition = CardEdition.UNKNOWN;
|
||||
@@ -1250,7 +1246,7 @@ public final class CardDb implements ICardDatabase, IDeckGenPool {
|
||||
}
|
||||
}
|
||||
if (paperCards.isEmpty()) {
|
||||
paperCards.add(new PaperCard(rules, CardEdition.UNKNOWN.getCode(), CardRarity.Special));
|
||||
paperCards.add(new PaperCard(rules, CardEdition.UNKNOWN_CODE, CardRarity.Special));
|
||||
}
|
||||
// 2. add them to db
|
||||
for (PaperCard paperCard : paperCards) {
|
||||
|
||||
@@ -262,7 +262,11 @@ public final class CardEdition implements Comparable<CardEdition> {
|
||||
|
||||
private final static SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd");
|
||||
|
||||
public static final CardEdition UNKNOWN = new CardEdition("1990-01-01", "???", "??", Type.UNKNOWN, "Undefined", FoilType.NOT_SUPPORTED, new CardInSet[]{});
|
||||
/**
|
||||
* Equivalent to the set code of CardEdition.UNKNOWN
|
||||
*/
|
||||
public static final String UNKNOWN_CODE = "???";
|
||||
public static final CardEdition UNKNOWN = new CardEdition("1990-01-01", UNKNOWN_CODE, "??", Type.UNKNOWN, "Undefined", FoilType.NOT_SUPPORTED, new CardInSet[]{});
|
||||
private Date date;
|
||||
private String code;
|
||||
private String code2;
|
||||
|
||||
@@ -396,6 +396,7 @@ public final class CardRules implements ICardCharacteristics {
|
||||
}
|
||||
|
||||
public int getSetColorID() {
|
||||
//Could someday generalize this to support other kinds of markings.
|
||||
return setColorID;
|
||||
}
|
||||
|
||||
|
||||
@@ -25,6 +25,8 @@ import forge.util.BinaryUtil;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
/**
|
||||
* <p>CardColor class.</p>
|
||||
@@ -291,14 +293,8 @@ public final class ColorSet implements Comparable<ColorSet>, Iterable<Byte>, Ser
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
if (this.orderWeight == -1) {
|
||||
return "n/a";
|
||||
}
|
||||
final String toReturn = MagicColor.toLongString(myColor);
|
||||
if (toReturn.equals(MagicColor.Constant.COLORLESS) && myColor != 0) {
|
||||
return "multi";
|
||||
}
|
||||
return toReturn;
|
||||
final ManaCostShard[] orderedShards = getOrderedShards();
|
||||
return Arrays.stream(orderedShards).map(ManaCostShard::toShortString).collect(Collectors.joining());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -376,6 +372,10 @@ public final class ColorSet implements Comparable<ColorSet>, Iterable<Byte>, Ser
|
||||
}
|
||||
}
|
||||
|
||||
public Stream<MagicColor.Color> stream() {
|
||||
return this.toEnumSet().stream();
|
||||
}
|
||||
|
||||
//Get array of mana cost shards for color set in the proper order
|
||||
public ManaCostShard[] getOrderedShards() {
|
||||
return shardOrderLookup[myColor];
|
||||
|
||||
@@ -5,43 +5,42 @@ import forge.item.PaperCard;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Date;
|
||||
import java.util.Map;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.stream.Stream;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Magic Cards Database.
|
||||
* --------------------
|
||||
* This interface defines the general API for Database Access and Cards' Lookup.
|
||||
* <p>
|
||||
* Methods for single Card's lookup currently support three alternative strategies:
|
||||
* 1. [getCard]: Card search based on a single card's attributes
|
||||
* (i.e. name, edition, art, collectorNumber)
|
||||
* <p>
|
||||
* 2. [getCardFromSet]: Card Lookup from a single Expansion set.
|
||||
* Particularly useful in Deck Editors when a specific Set is specified.
|
||||
* <p>
|
||||
* 3. [getCardFromEditions]: Card search considering a predefined `SetPreference` policy and/or a specified Date
|
||||
* when no expansion is specified for a card.
|
||||
* This method is particularly useful for Re-prints whenever no specific
|
||||
* Expansion is specified (e.g. in Deck Import) and a decision should be made
|
||||
* on which card to pick. This methods allows to adopt a SetPreference selection
|
||||
* policy to make this decision.
|
||||
* <p>
|
||||
* The API also includes methods to fetch Collection of Card (i.e. PaperCard instances):
|
||||
* - all cards (no filter)
|
||||
* - all unique cards (by name)
|
||||
* - all prints of a single card
|
||||
* - all cards from a single Expansion Set
|
||||
* - all cards compliant with a filter condition (i.e. Predicate)
|
||||
* <p>
|
||||
* Finally, various utility methods are supported:
|
||||
* - Get the foil version of a Card (if Any)
|
||||
* - Get the Order Number of a Card in an Expansion Set
|
||||
* - Get the number of Print/Arts for a card in a Set (useful for those exp. having multiple arts)
|
||||
* */
|
||||
public interface ICardDatabase extends Iterable<PaperCard> {
|
||||
/**
|
||||
* Magic Cards Database.
|
||||
* --------------------
|
||||
* This interface defines the general API for Database Access and Cards' Lookup.
|
||||
*
|
||||
* Methods for single Card's lookup currently support three alternative strategies:
|
||||
* 1. [getCard]: Card search based on a single card's attributes
|
||||
* (i.e. name, edition, art, collectorNumber)
|
||||
*
|
||||
* 2. [getCardFromSet]: Card Lookup from a single Expansion set.
|
||||
* Particularly useful in Deck Editors when a specific Set is specified.
|
||||
*
|
||||
* 3. [getCardFromEditions]: Card search considering a predefined `SetPreference` policy and/or a specified Date
|
||||
* when no expansion is specified for a card.
|
||||
* This method is particularly useful for Re-prints whenever no specific
|
||||
* Expansion is specified (e.g. in Deck Import) and a decision should be made
|
||||
* on which card to pick. This methods allows to adopt a SetPreference selection
|
||||
* policy to make this decision.
|
||||
*
|
||||
* The API also includes methods to fetch Collection of Card (i.e. PaperCard instances):
|
||||
* - all cards (no filter)
|
||||
* - all unique cards (by name)
|
||||
* - all prints of a single card
|
||||
* - all cards from a single Expansion Set
|
||||
* - all cards compliant with a filter condition (i.e. Predicate)
|
||||
*
|
||||
* Finally, various utility methods are supported:
|
||||
* - Get the foil version of a Card (if Any)
|
||||
* - Get the Order Number of a Card in an Expansion Set
|
||||
* - Get the number of Print/Arts for a card in a Set (useful for those exp. having multiple arts)
|
||||
* */
|
||||
|
||||
/* SINGLE CARD RETRIEVAL METHODS
|
||||
* ============================= */
|
||||
// 1. Card Lookup by attributes
|
||||
@@ -50,22 +49,19 @@ public interface ICardDatabase extends Iterable<PaperCard> {
|
||||
PaperCard getCard(String cardName, String edition, int artIndex);
|
||||
// [NEW Methods] Including the card CollectorNumber as criterion for DB lookup
|
||||
PaperCard getCard(String cardName, String edition, String collectorNumber);
|
||||
PaperCard getCard(String cardName, String edition, int artIndex, String collectorNumber);
|
||||
PaperCard getCard(String cardName, String edition, int artIndex, Set<String> colorID);
|
||||
PaperCard getCard(String cardName, String edition, int artIndex, Map<String, String> flags);
|
||||
|
||||
// 2. Card Lookup from a single Expansion Set
|
||||
PaperCard getCardFromSet(String cardName, CardEdition edition, boolean isFoil); // NOT yet used, included for API symmetry
|
||||
PaperCard getCardFromSet(String cardName, CardEdition edition, String collectorNumber, boolean isFoil);
|
||||
PaperCard getCardFromSet(String cardName, CardEdition edition, int artIndex, boolean isFoil);
|
||||
PaperCard getCardFromSet(String cardName, CardEdition edition, int artIndex, String collectorNumber, boolean isFoil);
|
||||
PaperCard getCardFromSet(String cardName, CardEdition edition, int artIndex, String collectorNumber, boolean isFoil, Set<String> colorID);
|
||||
|
||||
// 3. Card lookup based on CardArtPreference Selection Policy
|
||||
PaperCard getCardFromEditions(String cardName, CardArtPreference artPreference);
|
||||
PaperCard getCardFromEditions(String cardName, CardArtPreference artPreference, Predicate<PaperCard> filter);
|
||||
PaperCard getCardFromEditions(String cardName, CardArtPreference artPreference, int artIndex);
|
||||
PaperCard getCardFromEditions(String cardName, CardArtPreference artPreference, int artIndex, Predicate<PaperCard> filter);
|
||||
PaperCard getCardFromEditions(String cardName, CardArtPreference artPreference, int artIndex, Set<String> colorID);
|
||||
|
||||
// 4. Specialised Card Lookup on CardArtPreference Selection and Release Date
|
||||
PaperCard getCardFromEditionsReleasedBefore(String cardName, CardArtPreference artPreference, Date releaseDate);
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package forge.card;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import forge.deck.DeckRecognizer;
|
||||
|
||||
/**
|
||||
* Holds byte values for each color magic has.
|
||||
@@ -187,6 +188,12 @@ public final class MagicColor {
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public String getLocalizedName() {
|
||||
//Should probably move some of this logic back here, or at least to a more general location.
|
||||
return DeckRecognizer.getLocalisedMagicColorName(getName());
|
||||
}
|
||||
|
||||
public byte getColormask() {
|
||||
return colormask;
|
||||
}
|
||||
|
||||
@@ -94,6 +94,7 @@ public enum ManaCostShard {
|
||||
/** The cmpc. */
|
||||
private final float cmpc;
|
||||
private final String stringValue;
|
||||
private final String shortStringValue;
|
||||
|
||||
/** The image key. */
|
||||
private final String imageKey;
|
||||
@@ -125,6 +126,7 @@ public enum ManaCostShard {
|
||||
this.cmc = this.getCMC();
|
||||
this.cmpc = this.getCmpCost();
|
||||
this.stringValue = "{" + sValue + "}";
|
||||
this.shortStringValue = sValue;
|
||||
this.imageKey = imgKey;
|
||||
}
|
||||
|
||||
@@ -232,16 +234,21 @@ public enum ManaCostShard {
|
||||
return ManaCostShard.valueOf(atoms);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see java.lang.Object#toString()
|
||||
/**
|
||||
* @return the string representation of this shard - e.g. "{W}" "{2/U}" "{G/P}"
|
||||
*/
|
||||
@Override
|
||||
public final String toString() {
|
||||
return this.stringValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The string representation of this shard without brackets - e.g. "W" "2/U" "G/P"
|
||||
*/
|
||||
public final String toShortString() {
|
||||
return this.shortStringValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the cmc.
|
||||
*
|
||||
|
||||
@@ -52,7 +52,7 @@ public class CardPool extends ItemPool<PaperCard> {
|
||||
|
||||
public void add(final String cardRequest, final int amount) {
|
||||
CardDb.CardRequest request = CardDb.CardRequest.fromString(cardRequest);
|
||||
this.add(CardDb.CardRequest.compose(request.cardName, request.isFoil), request.edition, request.artIndex, amount, false, request.colorID);
|
||||
this.add(CardDb.CardRequest.compose(request.cardName, request.isFoil), request.edition, request.artIndex, amount, false, request.flags);
|
||||
}
|
||||
|
||||
public void add(final String cardName, final String setCode) {
|
||||
@@ -71,7 +71,7 @@ public class CardPool extends ItemPool<PaperCard> {
|
||||
public void add(String cardName, String setCode, int artIndex, final int amount) {
|
||||
this.add(cardName, setCode, artIndex, amount, false, null);
|
||||
}
|
||||
public void add(String cardName, String setCode, int artIndex, final int amount, boolean addAny, Set<String> colorID) {
|
||||
public void add(String cardName, String setCode, int artIndex, final int amount, boolean addAny, Map<String, String> flags) {
|
||||
Map<String, CardDb> dbs = StaticData.instance().getAvailableDatabases();
|
||||
PaperCard paperCard = null;
|
||||
String selectedDbName = "";
|
||||
@@ -81,7 +81,7 @@ public class CardPool extends ItemPool<PaperCard> {
|
||||
for (Map.Entry<String, CardDb> entry: dbs.entrySet()){
|
||||
String dbName = entry.getKey();
|
||||
CardDb db = entry.getValue();
|
||||
paperCard = db.getCard(cardName, setCode, artIndex, colorID);
|
||||
paperCard = db.getCard(cardName, setCode, artIndex, flags);
|
||||
if (paperCard != null) {
|
||||
selectedDbName = dbName;
|
||||
break;
|
||||
@@ -123,7 +123,7 @@ public class CardPool extends ItemPool<PaperCard> {
|
||||
int cnt = artGroups[i - 1];
|
||||
if (cnt <= 0)
|
||||
continue;
|
||||
PaperCard randomCard = cardDb.getCard(cardName, setCode, i, colorID);
|
||||
PaperCard randomCard = cardDb.getCard(cardName, setCode, i, flags);
|
||||
this.add(randomCard, cnt);
|
||||
}
|
||||
}
|
||||
@@ -430,7 +430,6 @@ public class CardPool extends ItemPool<PaperCard> {
|
||||
public String toCardList(String separator) {
|
||||
List<Entry<PaperCard, Integer>> main2sort = Lists.newArrayList(this);
|
||||
main2sort.sort(ItemPoolSorter.BY_NAME_THEN_SET);
|
||||
final CardDb commonDb = StaticData.instance().getCommonCards();
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
boolean isFirst = true;
|
||||
@@ -441,10 +440,8 @@ public class CardPool extends ItemPool<PaperCard> {
|
||||
else
|
||||
isFirst = false;
|
||||
|
||||
CardDb db = !e.getKey().getRules().isVariant() ? commonDb : StaticData.instance().getVariantCards();
|
||||
sb.append(e.getValue()).append(" ");
|
||||
db.appendCardToStringBuilder(e.getKey(), sb);
|
||||
|
||||
sb.append(CardDb.CardRequest.compose(e.getKey()));
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
@@ -463,20 +460,4 @@ public class CardPool extends ItemPool<PaperCard> {
|
||||
}
|
||||
return filteredPool;
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies a predicate to this CardPool's cards.
|
||||
* @param predicate the Predicate to apply to this CardPool
|
||||
* @return a new CardPool made from this CardPool with only the cards that agree with the provided Predicate
|
||||
*/
|
||||
public CardPool getFilteredPoolWithCardsCount(Predicate<PaperCard> predicate) {
|
||||
CardPool filteredPool = new CardPool();
|
||||
for (Entry<PaperCard, Integer> entry : this.items.entrySet()) {
|
||||
PaperCard pc = entry.getKey();
|
||||
int count = entry.getValue();
|
||||
if (predicate.test(pc))
|
||||
filteredPool.add(pc, count);
|
||||
}
|
||||
return filteredPool;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -247,7 +247,7 @@ public class Deck extends DeckBase implements Iterable<Entry<DeckSection, CardPo
|
||||
|
||||
Map<String, List<String>> referenceDeckLoadingMap;
|
||||
if (deferredSections != null) {
|
||||
this.validateDeferredSections();
|
||||
this.normalizeDeferredSections();
|
||||
referenceDeckLoadingMap = new HashMap<>(this.deferredSections);
|
||||
} else
|
||||
referenceDeckLoadingMap = new HashMap<>(loadedSections);
|
||||
@@ -267,7 +267,7 @@ public class Deck extends DeckBase implements Iterable<Entry<DeckSection, CardPo
|
||||
continue;
|
||||
final List<String> cardsInSection = s.getValue();
|
||||
ArrayList<String> cardNamesWithNoEdition = getAllCardNamesWithNoSpecifiedEdition(cardsInSection);
|
||||
if (cardNamesWithNoEdition.size() > 0) {
|
||||
if (!cardNamesWithNoEdition.isEmpty()) {
|
||||
includeCardsFromUnspecifiedSet = true;
|
||||
if (smartCardArtSelection)
|
||||
cardsWithNoEdition.put(sec, cardNamesWithNoEdition);
|
||||
@@ -281,10 +281,10 @@ public class Deck extends DeckBase implements Iterable<Entry<DeckSection, CardPo
|
||||
optimiseCardArtSelectionInDeckSections(cardsWithNoEdition);
|
||||
}
|
||||
|
||||
private void validateDeferredSections() {
|
||||
private void normalizeDeferredSections() {
|
||||
/*
|
||||
Construct a temporary (DeckSection, CardPool) Maps, to be sanitised and finalised
|
||||
before copying into `this.parts`. This sanitisation is applied because of the
|
||||
before copying into `this.parts`. This sanitization is applied because of the
|
||||
validation schema introduced in DeckSections.
|
||||
*/
|
||||
Map<String, List<String>> validatedSections = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
|
||||
@@ -296,61 +296,33 @@ public class Deck extends DeckBase implements Iterable<Entry<DeckSection, CardPo
|
||||
}
|
||||
|
||||
final List<String> cardsInSection = s.getValue();
|
||||
List<Pair<String, Integer>> originalCardRequests = CardPool.processCardList(cardsInSection);
|
||||
CardPool pool = CardPool.fromCardList(cardsInSection);
|
||||
if (pool.countDistinct() == 0)
|
||||
continue; // pool empty, no card has been found!
|
||||
|
||||
// Filter pool by applying DeckSection Validation schema for Card Types (to avoid inconsistencies)
|
||||
CardPool filteredPool = pool.getFilteredPoolWithCardsCount(deckSection::validate);
|
||||
// Add all the cards from ValidPool anyway!
|
||||
List<String> whiteList = validatedSections.getOrDefault(s.getKey(), null);
|
||||
if (whiteList == null)
|
||||
whiteList = new ArrayList<>();
|
||||
for (Entry<PaperCard, Integer> entry : filteredPool) {
|
||||
String poolRequest = getPoolRequest(entry, originalCardRequests);
|
||||
whiteList.add(poolRequest);
|
||||
List<String> validatedSection = validatedSections.computeIfAbsent(s.getKey(), (k) -> new ArrayList<>());
|
||||
for (Entry<PaperCard, Integer> entry : pool) {
|
||||
PaperCard card = entry.getKey();
|
||||
String normalizedRequest = getPoolRequest(entry);
|
||||
if(deckSection.validate(card))
|
||||
validatedSection.add(normalizedRequest);
|
||||
else {
|
||||
// Card was in the wrong section. Move it to the right section.
|
||||
DeckSection cardSection = DeckSection.matchingSection(card);
|
||||
assert(cardSection.validate(card)); //Card doesn't fit in the matchingSection?
|
||||
List<String> sectionCardList = validatedSections.computeIfAbsent(cardSection.name(), (k) -> new ArrayList<>());
|
||||
sectionCardList.add(normalizedRequest);
|
||||
}
|
||||
}
|
||||
validatedSections.put(s.getKey(), whiteList);
|
||||
|
||||
if (filteredPool.countDistinct() != pool.countDistinct()) {
|
||||
CardPool blackList = pool.getFilteredPoolWithCardsCount(input -> !(deckSection.validate(input)));
|
||||
|
||||
for (Entry<PaperCard, Integer> entry : blackList) {
|
||||
DeckSection cardSection = DeckSection.matchingSection(entry.getKey());
|
||||
String poolRequest = getPoolRequest(entry, originalCardRequests);
|
||||
List<String> sectionCardList = validatedSections.getOrDefault(cardSection.name(), null);
|
||||
if (sectionCardList == null)
|
||||
sectionCardList = new ArrayList<>();
|
||||
sectionCardList.add(poolRequest);
|
||||
validatedSections.put(cardSection.name(), sectionCardList);
|
||||
} // end for blacklist
|
||||
} // end if
|
||||
} // end main for on deferredSections
|
||||
|
||||
// Overwrite deferredSections
|
||||
this.deferredSections = validatedSections;
|
||||
}
|
||||
|
||||
private String getPoolRequest(Entry<PaperCard, Integer> entry, List<Pair<String, Integer>> originalCardRequests) {
|
||||
PaperCard card = entry.getKey();
|
||||
private String getPoolRequest(Entry<PaperCard, Integer> entry) {
|
||||
int amount = entry.getValue();
|
||||
String poolCardRequest = CardDb.CardRequest.compose(
|
||||
card.isFoil() ? CardDb.CardRequest.compose(card.getName(), true) : card.getName(),
|
||||
card.getEdition(), card.getArtIndex(), card.getColorID());
|
||||
String originalRequestCandidate = null;
|
||||
for (Pair<String, Integer> originalRequest : originalCardRequests){
|
||||
String cardRequest = originalRequest.getLeft();
|
||||
if (!StringUtils.startsWithIgnoreCase(poolCardRequest, cardRequest))
|
||||
continue;
|
||||
originalRequestCandidate = cardRequest;
|
||||
int cardAmount = originalRequest.getRight();
|
||||
if (amount == cardAmount)
|
||||
return String.format("%d %s", cardAmount, cardRequest);
|
||||
}
|
||||
// This is just in case, it should never happen as we're
|
||||
if (originalRequestCandidate != null)
|
||||
return String.format("%d %s", amount, originalRequestCandidate);
|
||||
String poolCardRequest = CardDb.CardRequest.compose(entry.getKey());
|
||||
return String.format("%d %s", amount, poolCardRequest);
|
||||
}
|
||||
|
||||
|
||||
@@ -987,7 +987,7 @@ public class DeckRecognizer {
|
||||
private static String getMagicColourLabel(MagicColor.Color magicColor) {
|
||||
if (magicColor == null) // Multicolour
|
||||
return String.format("%s {W}{U}{B}{R}{G}", getLocalisedMagicColorName("Multicolour"));
|
||||
return String.format("%s %s", getLocalisedMagicColorName(magicColor.getName()), magicColor.getSymbol());
|
||||
return String.format("%s %s", magicColor.getLocalizedName(), magicColor.getSymbol());
|
||||
}
|
||||
|
||||
private static final HashMap<Integer, String> manaSymbolsMap = new HashMap<Integer, String>() {{
|
||||
@@ -1006,8 +1006,8 @@ public class DeckRecognizer {
|
||||
if (magicColor2 == null || magicColor2 == MagicColor.Color.COLORLESS
|
||||
|| magicColor1 == MagicColor.Color.COLORLESS)
|
||||
return String.format("%s // %s", getMagicColourLabel(magicColor1), getMagicColourLabel(magicColor2));
|
||||
String localisedName1 = getLocalisedMagicColorName(magicColor1.getName());
|
||||
String localisedName2 = getLocalisedMagicColorName(magicColor2.getName());
|
||||
String localisedName1 = magicColor1.getLocalizedName();
|
||||
String localisedName2 = magicColor2.getLocalizedName();
|
||||
String comboManaSymbol = manaSymbolsMap.get(magicColor1.getColormask() | magicColor2.getColormask());
|
||||
return String.format("%s/%s {%s}", localisedName1, localisedName2, comboManaSymbol);
|
||||
}
|
||||
|
||||
@@ -88,7 +88,7 @@ public enum DeckSection {
|
||||
CardType t = card.getRules().getType();
|
||||
// NOTE: Same rules applies to both Deck and Side, despite "Conspiracy cards" are allowed
|
||||
// in the SideBoard (see Rule 313.2)
|
||||
// Those will be matched later, in case (see `Deck::validateDeferredSections`)
|
||||
// Those will be matched later, in case (see `Deck::normalizeDeferredSections`)
|
||||
return !t.isConspiracy() && !t.isDungeon() && !t.isPhenomenon() && !t.isPlane() && !t.isScheme() && !t.isVanguard();
|
||||
};
|
||||
|
||||
|
||||
@@ -61,6 +61,8 @@ public class DeckSerializer {
|
||||
}
|
||||
|
||||
for(Entry<DeckSection, CardPool> s : d) {
|
||||
if(s.getValue().isEmpty())
|
||||
continue;
|
||||
out.add(TextUtil.enclosedBracket(s.getKey().toString()));
|
||||
out.add(s.getValue().toCardList(System.lineSeparator()));
|
||||
}
|
||||
|
||||
@@ -2,10 +2,10 @@ package forge.item;
|
||||
|
||||
import forge.card.CardRarity;
|
||||
import forge.card.CardRules;
|
||||
import forge.card.ColorSet;
|
||||
import forge.card.ICardFace;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Set;
|
||||
|
||||
public interface IPaperCard extends InventoryItem, Serializable {
|
||||
|
||||
@@ -20,7 +20,7 @@ public interface IPaperCard extends InventoryItem, Serializable {
|
||||
String getEdition();
|
||||
String getCollectorNumber();
|
||||
String getFunctionalVariant();
|
||||
Set<String> getColorID();
|
||||
ColorSet getMarkedColors();
|
||||
int getArtIndex();
|
||||
boolean isFoil();
|
||||
boolean isToken();
|
||||
|
||||
@@ -28,8 +28,10 @@ import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.io.ObjectStreamException;
|
||||
import java.io.Serial;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* A lightweight version of a card that matches real-world cards, to use outside of games (eg. inventory, decks, trade).
|
||||
@@ -39,6 +41,7 @@ import java.util.Set;
|
||||
* @author Forge
|
||||
*/
|
||||
public class PaperCard implements Comparable<IPaperCard>, InventoryItemFromSet, IPaperCard {
|
||||
@Serial
|
||||
private static final long serialVersionUID = 2942081982620691205L;
|
||||
|
||||
// Reference to rules
|
||||
@@ -55,16 +58,15 @@ public class PaperCard implements Comparable<IPaperCard>, InventoryItemFromSet,
|
||||
private String artist;
|
||||
private final int artIndex;
|
||||
private final boolean foil;
|
||||
private Boolean hasImage;
|
||||
private final boolean noSell;
|
||||
private Set<String> colorID;
|
||||
private String sortableName;
|
||||
private final PaperCardFlags flags;
|
||||
private final String sortableName;
|
||||
private final String functionalVariant;
|
||||
|
||||
// Calculated fields are below:
|
||||
private transient CardRarity rarity; // rarity is given in ctor when set is assigned
|
||||
// Reference to a new instance of Self, but foiled!
|
||||
private transient PaperCard foiledVersion, noSellVersion;
|
||||
private transient PaperCard foiledVersion, noSellVersion, flaglessVersion;
|
||||
private transient Boolean hasImage;
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
@@ -89,8 +91,8 @@ public class PaperCard implements Comparable<IPaperCard>, InventoryItemFromSet,
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> getColorID() {
|
||||
return colorID;
|
||||
public ColorSet getMarkedColors() {
|
||||
return this.flags.markedColors;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -147,32 +149,32 @@ public class PaperCard implements Comparable<IPaperCard>, InventoryItemFromSet,
|
||||
return unFoiledVersion;
|
||||
}
|
||||
public PaperCard getNoSellVersion() {
|
||||
if (this.noSell)
|
||||
if (this.flags.noSellValue)
|
||||
return this;
|
||||
|
||||
if (this.noSellVersion == null) {
|
||||
this.noSellVersion = new PaperCard(this.rules, this.edition, this.rarity,
|
||||
this.artIndex, this.foil, String.valueOf(collectorNumber), this.artist, this.functionalVariant, true);
|
||||
}
|
||||
if (this.noSellVersion == null)
|
||||
this.noSellVersion = new PaperCard(this, this.flags.withNoSellValueFlag(true));
|
||||
return this.noSellVersion;
|
||||
}
|
||||
public PaperCard getSellable() {
|
||||
if (!this.noSell)
|
||||
return this;
|
||||
|
||||
PaperCard sellable = new PaperCard(this.rules, this.edition, this.rarity,
|
||||
this.artIndex, this.foil, String.valueOf(collectorNumber), this.artist, this.functionalVariant, false);
|
||||
return sellable;
|
||||
public PaperCard copyWithoutFlags() {
|
||||
if(this.flaglessVersion == null) {
|
||||
if(this.flags == PaperCardFlags.IDENTITY_FLAGS)
|
||||
this.flaglessVersion = this;
|
||||
else
|
||||
this.flaglessVersion = new PaperCard(this, null);
|
||||
}
|
||||
return flaglessVersion;
|
||||
}
|
||||
public PaperCard getColorIDVersion(Set<String> colors) {
|
||||
if (colors == null && this.colorID == null)
|
||||
public PaperCard copyWithFlags(Map<String, String> flags) {
|
||||
if(flags == null || flags.isEmpty())
|
||||
return this.copyWithoutFlags();
|
||||
return new PaperCard(this, new PaperCardFlags(flags));
|
||||
}
|
||||
public PaperCard copyWithMarkedColors(ColorSet colors) {
|
||||
if(Objects.equals(colors, this.flags.markedColors))
|
||||
return this;
|
||||
if (this.colorID != null && this.colorID.equals(colors))
|
||||
return this;
|
||||
if (colors != null && colors.equals(this.colorID))
|
||||
return this;
|
||||
return new PaperCard(this.rules, this.edition, this.rarity,
|
||||
this.artIndex, this.foil, String.valueOf(collectorNumber), this.artist, this.functionalVariant, this.noSell, colors);
|
||||
return new PaperCard(this, this.flags.withMarkedColors(colors));
|
||||
}
|
||||
@Override
|
||||
public String getItemType() {
|
||||
@@ -180,8 +182,12 @@ public class PaperCard implements Comparable<IPaperCard>, InventoryItemFromSet,
|
||||
return localizer.getMessage("lblCard");
|
||||
}
|
||||
|
||||
public boolean isNoSell() {
|
||||
return noSell;
|
||||
public PaperCardFlags getMarkedFlags() {
|
||||
return this.flags;
|
||||
}
|
||||
|
||||
public boolean hasNoSellValue() {
|
||||
return this.flags.noSellValue;
|
||||
}
|
||||
public boolean hasImage() {
|
||||
return hasImage(false);
|
||||
@@ -198,38 +204,41 @@ public class PaperCard implements Comparable<IPaperCard>, InventoryItemFromSet,
|
||||
IPaperCard.NO_COLLECTOR_NUMBER, IPaperCard.NO_ARTIST_NAME, IPaperCard.NO_FUNCTIONAL_VARIANT);
|
||||
}
|
||||
|
||||
public PaperCard(final PaperCard copyFrom, final PaperCardFlags flags) {
|
||||
this(copyFrom.rules, copyFrom.edition, copyFrom.rarity, copyFrom.artIndex, copyFrom.foil, copyFrom.collectorNumber,
|
||||
copyFrom.artist, copyFrom.functionalVariant, flags);
|
||||
this.flaglessVersion = copyFrom.flaglessVersion;
|
||||
}
|
||||
|
||||
public PaperCard(final CardRules rules0, final String edition0, final CardRarity rarity0,
|
||||
final int artIndex0, final boolean foil0, final String collectorNumber0,
|
||||
final String artist0, final String functionalVariant) {
|
||||
this(rules0, edition0, rarity0, artIndex0, foil0, collectorNumber0, artist0, functionalVariant, false);
|
||||
this(rules0, edition0, rarity0, artIndex0, foil0, collectorNumber0, artist0, functionalVariant, null);
|
||||
}
|
||||
|
||||
public PaperCard(final CardRules rules0, final String edition0, final CardRarity rarity0,
|
||||
final int artIndex0, final boolean foil0, final String collectorNumber0,
|
||||
final String artist0, final String functionalVariant, final boolean noSell0) {
|
||||
this(rules0, edition0, rarity0, artIndex0, foil0, collectorNumber0, artist0, functionalVariant, noSell0, null);
|
||||
}
|
||||
|
||||
public PaperCard(final CardRules rules0, final String edition0, final CardRarity rarity0,
|
||||
final int artIndex0, final boolean foil0, final String collectorNumber0,
|
||||
final String artist0, final String functionalVariant, final boolean noSell0, final Set<String> colorID0) {
|
||||
if (rules0 == null || edition0 == null || rarity0 == null) {
|
||||
protected PaperCard(final CardRules rules, final String edition, final CardRarity rarity,
|
||||
final int artIndex, final boolean foil, final String collectorNumber,
|
||||
final String artist, final String functionalVariant, final PaperCardFlags flags) {
|
||||
if (rules == null || edition == null || rarity == null) {
|
||||
throw new IllegalArgumentException("Cannot create card without rules, edition or rarity");
|
||||
}
|
||||
rules = rules0;
|
||||
name = rules0.getName();
|
||||
edition = edition0;
|
||||
artIndex = Math.max(artIndex0, IPaperCard.DEFAULT_ART_INDEX);
|
||||
foil = foil0;
|
||||
rarity = rarity0;
|
||||
artist = TextUtil.normalizeText(artist0);
|
||||
collectorNumber = (collectorNumber0 != null) && (collectorNumber0.length() > 0) ? collectorNumber0 : IPaperCard.NO_COLLECTOR_NUMBER;
|
||||
this.rules = rules;
|
||||
name = rules.getName();
|
||||
this.edition = edition;
|
||||
this.artIndex = Math.max(artIndex, IPaperCard.DEFAULT_ART_INDEX);
|
||||
this.foil = foil;
|
||||
this.rarity = rarity;
|
||||
this.artist = TextUtil.normalizeText(artist);
|
||||
this.collectorNumber = (collectorNumber != null && !collectorNumber.isEmpty()) ? collectorNumber : IPaperCard.NO_COLLECTOR_NUMBER;
|
||||
// If the user changes the language this will make cards sort by the old language until they restart the game.
|
||||
// This is a good tradeoff
|
||||
sortableName = TextUtil.toSortableName(CardTranslation.getTranslatedName(rules0.getName()));
|
||||
sortableName = TextUtil.toSortableName(CardTranslation.getTranslatedName(rules.getName()));
|
||||
this.functionalVariant = functionalVariant != null ? functionalVariant : IPaperCard.NO_FUNCTIONAL_VARIANT;
|
||||
noSell = noSell0;
|
||||
colorID = colorID0;
|
||||
|
||||
if(flags == null || flags.equals(PaperCardFlags.IDENTITY_FLAGS))
|
||||
this.flags = PaperCardFlags.IDENTITY_FLAGS;
|
||||
else
|
||||
this.flags = flags;
|
||||
}
|
||||
|
||||
public static PaperCard FAKE_CARD = new PaperCard(CardRules.getUnsupportedCardNamed("Fake Card"), "Fake Edition", CardRarity.Common);
|
||||
@@ -256,8 +265,7 @@ public class PaperCard implements Comparable<IPaperCard>, InventoryItemFromSet,
|
||||
}
|
||||
if (!getCollectorNumber().equals(other.getCollectorNumber()))
|
||||
return false;
|
||||
// colorID can be NULL
|
||||
if (getColorID() != other.getColorID())
|
||||
if (!Objects.equals(flags, other.flags))
|
||||
return false;
|
||||
return (other.foil == foil) && (other.artIndex == artIndex);
|
||||
}
|
||||
@@ -269,13 +277,7 @@ public class PaperCard implements Comparable<IPaperCard>, InventoryItemFromSet,
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int code = (name.hashCode() * 11) + (edition.hashCode() * 59) +
|
||||
(artIndex * 2) + (getCollectorNumber().hashCode() * 383);
|
||||
final int id = Optional.ofNullable(colorID).map(Set::hashCode).orElse(0);
|
||||
if (foil) {
|
||||
return code + id + 1;
|
||||
}
|
||||
return code + id;
|
||||
return Objects.hash(name, edition, collectorNumber, artIndex, foil, flags);
|
||||
}
|
||||
|
||||
// FIXME: Check
|
||||
@@ -339,6 +341,7 @@ public class PaperCard implements Comparable<IPaperCard>, InventoryItemFromSet,
|
||||
return Integer.compare(artIndex, o.getArtIndex());
|
||||
}
|
||||
|
||||
@Serial
|
||||
private void readObject(ObjectInputStream ois) throws ClassNotFoundException, IOException {
|
||||
// default deserialization
|
||||
ois.defaultReadObject();
|
||||
@@ -354,6 +357,14 @@ public class PaperCard implements Comparable<IPaperCard>, InventoryItemFromSet,
|
||||
rarity = pc.getRarity();
|
||||
}
|
||||
|
||||
@Serial
|
||||
private Object readResolve() throws ObjectStreamException {
|
||||
//If we deserialize an old PaperCard with no flags, reinitialize as a fresh copy to set default flags.
|
||||
if(this.flags == null)
|
||||
return new PaperCard(this, null);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getImageKey(boolean altState) {
|
||||
String normalizedName = StringUtils.stripAccents(name);
|
||||
@@ -493,4 +504,85 @@ public class PaperCard implements Comparable<IPaperCard>, InventoryItemFromSet,
|
||||
public boolean isRebalanced() {
|
||||
return StaticData.instance().isRebalanced(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Contains properties of a card which distinguish it from an otherwise identical copy of the card with the same
|
||||
* name, edition, and collector number. Examples include permanent markings on the card, and flags for Adventure
|
||||
* mode.
|
||||
*/
|
||||
public static class PaperCardFlags {
|
||||
/**
|
||||
* Chosen colors, for cards like Cryptic Spires.
|
||||
*/
|
||||
public final ColorSet markedColors;
|
||||
/**
|
||||
* Removes the sell value of the card in Adventure mode.
|
||||
*/
|
||||
public final boolean noSellValue;
|
||||
|
||||
//TODO: Could probably move foil here.
|
||||
|
||||
static final PaperCardFlags IDENTITY_FLAGS = new PaperCardFlags(Map.of());
|
||||
|
||||
protected PaperCardFlags(Map<String, String> flags) {
|
||||
if(flags.containsKey("markedColors"))
|
||||
markedColors = ColorSet.fromNames(flags.get("markedColors").split(""));
|
||||
else
|
||||
markedColors = null;
|
||||
noSellValue = flags.containsKey("noSellValue");
|
||||
}
|
||||
|
||||
//Copy constructor. There are some better ways to do this, and they should be explored once we have more than 4
|
||||
//or 5 fields here. Just need to ensure it's impossible to accidentally change a field while the PaperCardFlags
|
||||
//object is in use.
|
||||
private PaperCardFlags(PaperCardFlags copyFrom, ColorSet markedColors, Boolean noSellValue) {
|
||||
if(markedColors == null)
|
||||
markedColors = copyFrom.markedColors;
|
||||
else if(markedColors.isColorless())
|
||||
markedColors = null;
|
||||
this.markedColors = markedColors;
|
||||
this.noSellValue = noSellValue != null ? noSellValue : copyFrom.noSellValue;
|
||||
}
|
||||
|
||||
public PaperCardFlags withMarkedColors(ColorSet markedColors) {
|
||||
if(markedColors == null)
|
||||
markedColors = ColorSet.getNullColor();
|
||||
return new PaperCardFlags(this, markedColors, null);
|
||||
}
|
||||
|
||||
public PaperCardFlags withNoSellValueFlag(boolean noSellValue) {
|
||||
return new PaperCardFlags(this, null, noSellValue);
|
||||
}
|
||||
|
||||
private Map<String, String> asMap;
|
||||
public Map<String, String> toMap() {
|
||||
if(asMap != null)
|
||||
return asMap;
|
||||
Map<String, String> out = new HashMap<>();
|
||||
if(markedColors != null && !markedColors.isColorless())
|
||||
out.put("markedColors", markedColors.toString());
|
||||
if(noSellValue)
|
||||
out.put("noSellValue", "true");
|
||||
asMap = out;
|
||||
return out;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return this.toMap().entrySet().stream()
|
||||
.map((e) -> e.getKey() + "=" + e.getValue())
|
||||
.collect(Collectors.joining("\t"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (!(o instanceof PaperCardFlags that)) return false;
|
||||
return noSellValue == that.noSellValue && Objects.equals(markedColors, that.markedColors);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(markedColors, noSellValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,7 +7,6 @@ import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Locale;
|
||||
import java.util.Set;
|
||||
|
||||
public class PaperToken implements InventoryItemFromSet, IPaperCard {
|
||||
private static final long serialVersionUID = 1L;
|
||||
@@ -153,7 +152,7 @@ public class PaperToken implements InventoryItemFromSet, IPaperCard {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> getColorID() {
|
||||
public ColorSet getMarkedColors() {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@@ -269,6 +269,13 @@ public class ItemPool<T extends InventoryItem> implements Iterable<Entry<T, Inte
|
||||
// need not set out-of-sync: either remove did set, or nothing was removed
|
||||
}
|
||||
|
||||
public void removeIf(Predicate<T> test) {
|
||||
for (final T item : items.keySet()) {
|
||||
if (test.test(item))
|
||||
remove(item);
|
||||
}
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
items.clear();
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ import forge.GameCommand;
|
||||
import forge.StaticData;
|
||||
import forge.card.CardStateName;
|
||||
import forge.card.CardType.Supertype;
|
||||
import forge.card.ColorSet;
|
||||
import forge.card.GamePieceType;
|
||||
import forge.card.MagicColor;
|
||||
import forge.deck.DeckSection;
|
||||
@@ -541,8 +542,8 @@ public class GameAction {
|
||||
game.addLeftGraveyardThisTurn(lastKnownInfo);
|
||||
}
|
||||
|
||||
if (c.hasChosenColorSpire()) {
|
||||
copied.setChosenColorID(ImmutableSet.copyOf(c.getChosenColorID()));
|
||||
if (c.hasMarkedColor()) {
|
||||
copied.setMarkedColors(c.getMarkedColors());
|
||||
}
|
||||
|
||||
copied.updateStateForView();
|
||||
@@ -2414,15 +2415,14 @@ public class GameAction {
|
||||
for (Card c : spires) {
|
||||
// TODO: only do this for the AI, for the player part, get the encoded color from the deck file and pass
|
||||
// it to either player or the papercard object so it feels like rule based for the player side..
|
||||
if (!c.hasChosenColorSpire()) {
|
||||
if (!c.hasMarkedColor()) {
|
||||
if (takesAction.isAI()) {
|
||||
List<String> colorChoices = new ArrayList<>(MagicColor.Constant.ONLY_COLORS);
|
||||
String prompt = CardTranslation.getTranslatedName(c.getName()) + ": " +
|
||||
Localizer.getInstance().getMessage("lblChooseNColors", Lang.getNumeral(2));
|
||||
SpellAbility sa = new SpellAbility.EmptySa(ApiType.ChooseColor, c, takesAction);
|
||||
sa.putParam("AILogic", "MostProminentInComputerDeck");
|
||||
Set<String> chosenColors = new HashSet<>(takesAction.getController().chooseColors(prompt, sa, 2, 2, colorChoices));
|
||||
c.setChosenColorID(chosenColors);
|
||||
ColorSet chosenColors = ColorSet.fromNames(takesAction.getController().chooseColors(prompt, sa, 2, 2, MagicColor.Constant.ONLY_COLORS));
|
||||
c.setMarkedColors(chosenColors);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -200,7 +200,7 @@ public class CloneEffect extends SpellAbilityEffect {
|
||||
tgtCard.addRemembered(cardToCopy);
|
||||
}
|
||||
// spire
|
||||
tgtCard.setChosenColorID(cardToCopy.getChosenColorID());
|
||||
tgtCard.setMarkedColors(cardToCopy.getMarkedColors());
|
||||
|
||||
game.fireEvent(new GameEventCardStatsChanged(tgtCard));
|
||||
}
|
||||
|
||||
@@ -314,7 +314,7 @@ public class CopyPermanentEffect extends TokenEffectBase {
|
||||
}
|
||||
}
|
||||
// spire
|
||||
copy.setChosenColorID(original.getChosenColorID());
|
||||
copy.setMarkedColors(original.getMarkedColors());
|
||||
|
||||
copy.setTokenSpawningAbility(sa);
|
||||
copy.setGamePieceType(GamePieceType.TOKEN);
|
||||
|
||||
@@ -296,7 +296,7 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars, ITr
|
||||
private String chosenType2 = "";
|
||||
private List<String> notedTypes = new ArrayList<>();
|
||||
private List<String> chosenColors;
|
||||
private Set<String> chosenColorID;
|
||||
private ColorSet markedColor;
|
||||
private List<String> chosenName = new ArrayList<>();
|
||||
private Integer chosenNumber;
|
||||
private Player chosenPlayer;
|
||||
@@ -409,7 +409,7 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars, ITr
|
||||
view.updateClassLevel(this);
|
||||
view.updateDraftAction(this);
|
||||
if (paperCard != null)
|
||||
setChosenColorID(paperCard.getColorID());
|
||||
setMarkedColors(paperCard.getMarkedColors());
|
||||
}
|
||||
|
||||
public int getHiddenId() {
|
||||
@@ -2231,18 +2231,18 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars, ITr
|
||||
public boolean hasChosenColor(String s) {
|
||||
return chosenColors != null && chosenColors.contains(s);
|
||||
}
|
||||
public final Set<String> getChosenColorID() {
|
||||
if (chosenColorID == null) {
|
||||
return Sets.newHashSet();
|
||||
public final ColorSet getMarkedColors() {
|
||||
if (markedColor == null) {
|
||||
return ColorSet.getNullColor();
|
||||
}
|
||||
return chosenColorID;
|
||||
return markedColor;
|
||||
}
|
||||
public final void setChosenColorID(final Set<String> s) {
|
||||
chosenColorID = s;
|
||||
view.updateChosenColorID(this);
|
||||
public final void setMarkedColors(final ColorSet s) {
|
||||
markedColor = s;
|
||||
view.updateMarkedColors(this);
|
||||
}
|
||||
public boolean hasChosenColorSpire() {
|
||||
return chosenColorID != null && !chosenColorID.isEmpty();
|
||||
public boolean hasMarkedColor() {
|
||||
return markedColor != null && !markedColor.isColorless();
|
||||
}
|
||||
public final Card getChosenCard() {
|
||||
return getChosenCards().getFirst();
|
||||
|
||||
@@ -77,7 +77,7 @@ public class CardState extends GameObject implements IHasSVars, ITranslatable {
|
||||
private KeywordCollection cachedKeywords = new KeywordCollection();
|
||||
|
||||
private CardRarity rarity = CardRarity.Unknown;
|
||||
private String setCode = CardEdition.UNKNOWN.getCode();
|
||||
private String setCode = CardEdition.UNKNOWN_CODE;
|
||||
|
||||
private final CardStateView view;
|
||||
private final Card card;
|
||||
|
||||
@@ -433,11 +433,11 @@ public class CardView extends GameEntityView {
|
||||
void updateChosenColors(Card c) {
|
||||
set(TrackableProperty.ChosenColors, c.getChosenColors());
|
||||
}
|
||||
public Set<String> getChosenColorID() {
|
||||
return get(TrackableProperty.ChosenColorID);
|
||||
public ColorSet getMarkedColors() {
|
||||
return get(TrackableProperty.MarkedColors);
|
||||
}
|
||||
void updateChosenColorID(Card c) {
|
||||
set(TrackableProperty.ChosenColorID, c.getChosenColorID());
|
||||
void updateMarkedColors(Card c) {
|
||||
set(TrackableProperty.MarkedColors, c.getMarkedColors());
|
||||
}
|
||||
public FCollectionView<CardView> getMergedCardsCollection() {
|
||||
return get(TrackableProperty.MergedCardsCollection);
|
||||
|
||||
@@ -703,10 +703,10 @@ public class AbilityManaPart implements java.io.Serializable {
|
||||
return "";
|
||||
}
|
||||
Card card = sa.getHostCard();
|
||||
if (card != null && card.hasChosenColorSpire()) {
|
||||
if (card != null && card.hasMarkedColor()) {
|
||||
StringBuilder values = new StringBuilder();
|
||||
for (String s : card.getChosenColorID()) {
|
||||
values.append(MagicColor.toShortString(MagicColor.fromName(s))).append(" ");
|
||||
for (byte c : card.getMarkedColors()) {
|
||||
values.append(MagicColor.toShortString(c)).append(" ");
|
||||
}
|
||||
return values.toString();
|
||||
}
|
||||
|
||||
@@ -67,7 +67,6 @@ public enum TrackableProperty {
|
||||
ChosenType2(TrackableTypes.StringType),
|
||||
NotedTypes(TrackableTypes.StringListType),
|
||||
ChosenColors(TrackableTypes.StringListType),
|
||||
ChosenColorID(TrackableTypes.StringSetType),
|
||||
ChosenCards(TrackableTypes.CardViewCollectionType),
|
||||
ChosenNumber(TrackableTypes.StringType),
|
||||
StoredRolls(TrackableTypes.StringListType),
|
||||
@@ -102,6 +101,7 @@ public enum TrackableProperty {
|
||||
NeedsTransformAnimation(TrackableTypes.BooleanType, FreezeMode.IgnoresFreeze),
|
||||
NeedsUntapAnimation(TrackableTypes.BooleanType, FreezeMode.IgnoresFreeze),
|
||||
NeedsTapAnimation(TrackableTypes.BooleanType, FreezeMode.IgnoresFreeze),
|
||||
MarkedColors(TrackableTypes.ColorSetType),
|
||||
|
||||
ImprintedCards(TrackableTypes.CardViewCollectionType),
|
||||
ExiledCards(TrackableTypes.CardViewCollectionType),
|
||||
|
||||
@@ -182,7 +182,7 @@ public class GuiDesktop implements IGuiBase {
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> List<T> getChoices(final String message, final int min, final int max, final Collection<T> choices, final T selected, final Function<T, String> display) {
|
||||
public <T> List<T> getChoices(final String message, final int min, final int max, final Collection<T> choices, final Collection<T> selected, final Function<T, String> display) {
|
||||
/*if ((choices != null && !choices.isEmpty() && choices.iterator().next() instanceof GameObject) || selected instanceof GameObject) {
|
||||
System.err.println("Warning: GameObject passed to GUI! Printing stack trace.");
|
||||
Thread.dumpStack();
|
||||
|
||||
@@ -214,7 +214,7 @@ public class CardDetailPanel extends SkinnedPanel {
|
||||
set = state.getSetCode();
|
||||
rarity = state.getRarity();
|
||||
} else {
|
||||
set = CardEdition.UNKNOWN.getCode();
|
||||
set = CardEdition.UNKNOWN_CODE;
|
||||
rarity = CardRarity.Unknown;
|
||||
}
|
||||
setInfoLabel.setText(set);
|
||||
|
||||
@@ -134,10 +134,10 @@ public class GuiChoose {
|
||||
return getChoices(message, min, max, choices, null, null);
|
||||
}
|
||||
|
||||
public static <T> List<T> getChoices(final String message, final int min, final int max, final Collection<T> choices, final T selected, final Function<T, String> display) {
|
||||
public static <T> List<T> getChoices(final String message, final int min, final int max, final Collection<T> choices, final Collection<T> selected, final Function<T, String> display) {
|
||||
return getChoices(message, min, max, choices, selected, display, null);
|
||||
}
|
||||
public static <T> List<T> getChoices(final String message, final int min, final int max, final Collection<T> choices, final T selected, final Function<T, String> display, final CMatchUI matchUI) {
|
||||
public static <T> List<T> getChoices(final String message, final int min, final int max, final Collection<T> choices, final Collection<T> selected, final Function<T, String> display, final CMatchUI matchUI) {
|
||||
if (choices == null || choices.isEmpty()) {
|
||||
if (min == 0) {
|
||||
return new ArrayList<>();
|
||||
|
||||
@@ -152,16 +152,13 @@ public class ListChooser<T> {
|
||||
|
||||
/** @return boolean */
|
||||
public boolean show() {
|
||||
return show(list.get(0));
|
||||
return show(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows the dialog and returns after the dialog was closed.
|
||||
*
|
||||
* @param index0 index to select when shown
|
||||
* @return a boolean.
|
||||
*/
|
||||
public boolean show(final T item) {
|
||||
public boolean show(final Collection<T> item) {
|
||||
if (this.called) {
|
||||
throw new IllegalStateException("Already shown");
|
||||
}
|
||||
@@ -169,8 +166,12 @@ public class ListChooser<T> {
|
||||
do {
|
||||
//invoke later so selected item not set until dialog open
|
||||
SwingUtilities.invokeLater(() -> {
|
||||
if (list.contains(item)) {
|
||||
lstChoices.setSelectedValue(item, true);
|
||||
if (item != null) {
|
||||
int[] indices = item.stream()
|
||||
.mapToInt(list::indexOf)
|
||||
.filter(i -> i >= 0)
|
||||
.toArray();
|
||||
lstChoices.setSelectedIndices(indices);
|
||||
}
|
||||
else {
|
||||
lstChoices.setSelectedIndex(0);
|
||||
|
||||
@@ -20,16 +20,15 @@ package forge.screens.deckeditor.controllers;
|
||||
import java.awt.Toolkit;
|
||||
import java.awt.event.InputEvent;
|
||||
import java.awt.event.KeyEvent;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.swing.JMenu;
|
||||
import javax.swing.JPopupMenu;
|
||||
import javax.swing.KeyStroke;
|
||||
import javax.swing.SwingUtilities;
|
||||
|
||||
import forge.card.ColorSet;
|
||||
import forge.card.MagicColor;
|
||||
import forge.deck.CardPool;
|
||||
import forge.deck.Deck;
|
||||
@@ -582,9 +581,9 @@ public abstract class ACEditorBase<TItem extends InventoryItem, TModel extends D
|
||||
int val;
|
||||
if ((val = existingCard.getRules().getSetColorID()) > 0) {
|
||||
GuiUtils.addMenuItem(menu, label, null, () -> {
|
||||
Set<String> colors = new HashSet<>(GuiChoose.getChoices(localizer.getMessage("lblChooseNColors", Lang.getNumeral(val)), val, val, MagicColor.Constant.ONLY_COLORS));
|
||||
List<String> colors = GuiChoose.getChoices(localizer.getMessage("lblChooseNColors", Lang.getNumeral(val)), val, val, MagicColor.Constant.ONLY_COLORS);
|
||||
// make an updated version
|
||||
PaperCard updated = existingCard.getColorIDVersion(colors);
|
||||
PaperCard updated = existingCard.copyWithMarkedColors(ColorSet.fromNames(colors));
|
||||
// remove *quantity* instances of existing card
|
||||
CDeckEditorUI.SINGLETON_INSTANCE.removeSelectedCards(false, 1);
|
||||
// add *quantity* into the deck and set them as selected
|
||||
|
||||
@@ -24,7 +24,6 @@ import java.awt.image.BufferedImage;
|
||||
import java.util.*;
|
||||
import java.util.List;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import java.util.function.Function;
|
||||
|
||||
@@ -1072,7 +1071,7 @@ public final class CMatchUI
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> List<T> getChoices(final String message, final int min, final int max, final List<T> choices, final T selected, final Function<T, String> display) {
|
||||
public <T> List<T> getChoices(final String message, final int min, final int max, final List<T> choices, final List<T> selected, final Function<T, String> display) {
|
||||
/*if ((choices != null && !choices.isEmpty() && choices.iterator().next() instanceof GameObject) || selected instanceof GameObject) {
|
||||
System.err.println("Warning: GameObject passed to GUI! Printing stack trace.");
|
||||
Thread.dumpStack();
|
||||
|
||||
@@ -277,21 +277,6 @@ public class CardDbCardMockTestCase extends CardMockTestCase {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetCardByNameSetArtIndexAndCollectorNumber() {
|
||||
// MultiArt Card
|
||||
PaperCard card;
|
||||
for (int i = 0; i < 4; i++) {
|
||||
int artIndex = i + 1;
|
||||
card = this.cardDb.getCard(cardNameHymnToTourach, editionHymnToTourach, artIndex,
|
||||
collectorNumbersHymnToTourach[i]);
|
||||
assertEquals(card.getName(), cardNameHymnToTourach);
|
||||
assertEquals(card.getEdition(), editionHymnToTourach);
|
||||
assertEquals(card.getCollectorNumber(), collectorNumbersHymnToTourach[i]);
|
||||
assertEquals(card.getArtIndex(), artIndex);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNullIsReturnedWithWrongInfo() {
|
||||
String wrongEditionCode = "M11";
|
||||
@@ -307,11 +292,6 @@ public class CardDbCardMockTestCase extends CardMockTestCase {
|
||||
// Wrong collector number
|
||||
card = this.cardDb.getCard(cardNameShivanDragon, editionShivanDragon, "wrongCN");
|
||||
assertNull(card);
|
||||
// wrong artIndex or collector number in getCard Full Info
|
||||
card = this.cardDb.getCard(cardNameShivanDragon, editionShivanDragon, 3, collNrShivanDragon);
|
||||
assertNull(card);
|
||||
card = this.cardDb.getCard(cardNameShivanDragon, editionShivanDragon, 1, "wrongCN");
|
||||
assertNull(card);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -2105,7 +2085,7 @@ public class CardDbCardMockTestCase extends CardMockTestCase {
|
||||
public void testGetCardFromUnknownSet() {
|
||||
String unknownCardName = "Unknown Card Name";
|
||||
PaperCard unknownCard = new PaperCard(CardRules.getUnsupportedCardNamed(unknownCardName),
|
||||
CardEdition.UNKNOWN.getCode(), CardRarity.Unknown);
|
||||
CardEdition.UNKNOWN_CODE, CardRarity.Unknown);
|
||||
this.cardDb.addCard(unknownCard);
|
||||
assertTrue(this.cardDb.getAllCards().contains(unknownCard));
|
||||
assertNotNull(this.cardDb.getAllCards(unknownCardName));
|
||||
@@ -2114,7 +2094,7 @@ public class CardDbCardMockTestCase extends CardMockTestCase {
|
||||
PaperCard retrievedPaperCard = this.cardDb.getCard(unknownCardName);
|
||||
assertNotNull(retrievedPaperCard);
|
||||
assertEquals(retrievedPaperCard.getName(), unknownCardName);
|
||||
assertEquals(retrievedPaperCard.getEdition(), CardEdition.UNKNOWN.getCode());
|
||||
assertEquals(retrievedPaperCard.getEdition(), CardEdition.UNKNOWN_CODE);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -197,7 +197,7 @@ public class GuiMobile implements IGuiBase {
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> List<T> getChoices(final String message, final int min, final int max, final Collection<T> choices, final T selected, final Function<T, String> display) {
|
||||
public <T> List<T> getChoices(final String message, final int min, final int max, final Collection<T> choices, final Collection<T> selected, final Function<T, String> display) {
|
||||
return new WaitCallback<List<T>>() {
|
||||
@Override
|
||||
public void run() {
|
||||
|
||||
@@ -120,7 +120,6 @@ public class AdventurePlayer implements Serializable, SaveFileContent {
|
||||
statistic.clear();
|
||||
newCards.clear();
|
||||
autoSellCards.clear();
|
||||
noSellCards.clear();
|
||||
AdventureEventController.clear();
|
||||
AdventureQuestController.clear();
|
||||
}
|
||||
@@ -134,7 +133,6 @@ public class AdventurePlayer implements Serializable, SaveFileContent {
|
||||
|
||||
private final ItemPool<PaperCard> newCards = new ItemPool<>(PaperCard.class);
|
||||
public final ItemPool<PaperCard> autoSellCards = new ItemPool<>(PaperCard.class);
|
||||
public final ItemPool<PaperCard> noSellCards = new ItemPool<>(PaperCard.class);
|
||||
|
||||
public void create(String n, Deck startingDeck, boolean male, int race, int avatar, boolean isFantasy, boolean isUsingCustomDeck, DifficultyData difficultyData) {
|
||||
clear();
|
||||
@@ -471,10 +469,43 @@ public class AdventurePlayer implements Serializable, SaveFileContent {
|
||||
}
|
||||
}
|
||||
if (data.containsKey("noSellCards")) {
|
||||
//Legacy list of unsellable cards. Now done via CardRequest flags. Convert the corresponding cards.
|
||||
PaperCard[] items = (PaperCard[]) data.readObject("noSellCards");
|
||||
for (PaperCard item : items) {
|
||||
if (item != null)
|
||||
noSellCards.add(item.getNoSellVersion());
|
||||
CardPool noSellPool = new CardPool();
|
||||
noSellPool.addAllFlat(List.of(items));
|
||||
for (Map.Entry<PaperCard, Integer> noSellEntry : noSellPool) {
|
||||
PaperCard item = noSellEntry.getKey();
|
||||
if (item == null)
|
||||
continue;
|
||||
int totalCopies = cards.count(item);
|
||||
int noSellCopies = Math.min(noSellEntry.getValue(), totalCopies);
|
||||
if (!cards.remove(item, noSellCopies)) {
|
||||
System.err.printf("Failed to update noSellValue flag - %s%n", item);
|
||||
continue;
|
||||
}
|
||||
|
||||
int remainingSellableCopies = totalCopies - noSellCopies;
|
||||
|
||||
PaperCard noSellVersion = item.getNoSellVersion();
|
||||
cards.add(noSellVersion, noSellCopies);
|
||||
|
||||
System.out.printf("Converted legacy noSellCards item - %s (%d / %d copies)%n", item, noSellCopies, totalCopies);
|
||||
|
||||
//Also go through their decks and update cards there.
|
||||
for (Deck deck : decks) {
|
||||
int inUse = 0;
|
||||
for (Map.Entry<DeckSection, CardPool> section : deck) {
|
||||
CardPool pool = section.getValue();
|
||||
inUse += pool.count(item);
|
||||
if(inUse > remainingSellableCopies) {
|
||||
int toConvert = inUse - remainingSellableCopies;
|
||||
pool.remove(item, toConvert);
|
||||
pool.add(noSellVersion, toConvert);
|
||||
System.out.printf("- Converted %d copies in deck - %s/%s%n", toConvert, deck.getName(), section.getKey());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
if (data.containsKey("autoSellCards")) {
|
||||
@@ -582,7 +613,6 @@ public class AdventurePlayer implements Serializable, SaveFileContent {
|
||||
|
||||
data.storeObject("newCards", newCards.toFlatList().toArray(new PaperCard[0]));
|
||||
data.storeObject("autoSellCards", autoSellCards.toFlatList().toArray(new PaperCard[0]));
|
||||
data.storeObject("noSellCards", noSellCards.toFlatList().toArray(new PaperCard[0]));
|
||||
|
||||
return data;
|
||||
}
|
||||
@@ -636,11 +666,6 @@ public class AdventurePlayer implements Serializable, SaveFileContent {
|
||||
if (reward.isAutoSell()) {
|
||||
autoSellCards.add(reward.getCard());
|
||||
refreshEditor();
|
||||
} else if (reward.isNoSell()) {
|
||||
if (reward.getCard() != null) {
|
||||
noSellCards.add(reward.getCard().getNoSellVersion());
|
||||
refreshEditor();
|
||||
}
|
||||
}
|
||||
break;
|
||||
case Gold:
|
||||
@@ -908,8 +933,7 @@ public class AdventurePlayer implements Serializable, SaveFileContent {
|
||||
}
|
||||
|
||||
public int cardSellPrice(PaperCard card) {
|
||||
int valuable = cards.count(card) - noSellCards.count(card);
|
||||
if (valuable == 0) {
|
||||
if (card.hasNoSellValue()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -920,23 +944,13 @@ public class AdventurePlayer implements Serializable, SaveFileContent {
|
||||
}
|
||||
|
||||
public int sellCard(PaperCard card, Integer result, boolean addGold) {
|
||||
// When selling cards, always try to sell cards worth something before selling cards that aren't worth anything
|
||||
if (result == null || result < 1) return 0;
|
||||
if (result == null || result < 1)
|
||||
return 0;
|
||||
|
||||
float earned = 0;
|
||||
|
||||
int valuableCount = cards.count(card) - noSellCards.count(card);
|
||||
int noValueToSell = result - valuableCount;
|
||||
int amountValuableToSell = Math.min(result, valuableCount);
|
||||
|
||||
if (amountValuableToSell > 0) {
|
||||
earned += cardSellPrice(card) * amountValuableToSell;
|
||||
cards.remove(card, amountValuableToSell);
|
||||
}
|
||||
if (noValueToSell > 0) {
|
||||
cards.remove(card, noValueToSell);
|
||||
noSellCards.remove(card, noValueToSell);
|
||||
}
|
||||
int amountToSell = Math.min(result, cards.count(card));
|
||||
if(!cards.remove(card, amountToSell))
|
||||
return 0; //Failed to sell?
|
||||
float earned = cardSellPrice(card) * amountToSell;
|
||||
|
||||
if (addGold) {
|
||||
addGold((int) earned);
|
||||
@@ -1198,10 +1212,6 @@ public class AdventurePlayer implements Serializable, SaveFileContent {
|
||||
return autoSellCards;
|
||||
}
|
||||
|
||||
public ItemPool<PaperCard> getNoSellCards() {
|
||||
return noSellCards;
|
||||
}
|
||||
|
||||
public ItemPool<PaperCard> getSellableCards() {
|
||||
ItemPool<PaperCard> sellableCards = new ItemPool<>(PaperCard.class);
|
||||
sellableCards.addAllFlat(cards.toFlatList());
|
||||
@@ -1236,7 +1246,6 @@ public class AdventurePlayer implements Serializable, SaveFileContent {
|
||||
collectionCards.addAll(cards);
|
||||
if (!allCards) {
|
||||
collectionCards.removeAll(autoSellCards);
|
||||
collectionCards.removeAll(noSellCards);
|
||||
}
|
||||
|
||||
return collectionCards;
|
||||
|
||||
@@ -211,14 +211,13 @@ public class AdventureDeckEditor extends TabPageScreen<AdventureDeckEditor> {
|
||||
});
|
||||
}
|
||||
|
||||
int noSellCount = Current.player().noSellCards.count(card);
|
||||
int autoSellCount = Current.player().autoSellCards.count(card);
|
||||
int sellableCount = Current.player().getSellableCards().count(card);
|
||||
|
||||
if (noSellCount > 0) {
|
||||
FMenuItem unsellableCount = new FMenuItem(Forge.getLocalizer().getMessage("lblUnsellableCount", noSellCount), null, null);
|
||||
unsellableCount.setEnabled(false);
|
||||
menu.addItem(unsellableCount);
|
||||
if (card.hasNoSellValue()) {
|
||||
FMenuItem unsellableIndicator = new FMenuItem(Forge.getLocalizer().getMessage("lblUnsellable"), null, null);
|
||||
unsellableIndicator.setEnabled(false);
|
||||
menu.addItem(unsellableIndicator);
|
||||
}
|
||||
|
||||
if (sellableCount > 0) {
|
||||
@@ -248,12 +247,13 @@ public class AdventureDeckEditor extends TabPageScreen<AdventureDeckEditor> {
|
||||
if (showCollectionCards) {
|
||||
collectionPool.addAllFlat(AdventurePlayer.current().getCollectionCards(false).toFlatList());
|
||||
}
|
||||
if (showNoSellCards) {
|
||||
collectionPool.addAllFlat(AdventurePlayer.current().getNoSellCards().toFlatList());
|
||||
collectionPool.removeAllFlat(cardsInUse.toFlatList());
|
||||
} else {
|
||||
cardsInUse.removeAllFlat(AdventurePlayer.current().getNoSellCards().toFlatList());
|
||||
collectionPool.removeAllFlat(cardsInUse.toFlatList());
|
||||
else if(showNoSellCards) {
|
||||
collectionPool.addAll(AdventurePlayer.current().getCollectionCards(false).getFilteredPool(PaperCard::hasNoSellValue));
|
||||
}
|
||||
|
||||
collectionPool.removeAllFlat(cardsInUse.toFlatList());
|
||||
if (!showNoSellCards) {
|
||||
collectionPool.removeIf(PaperCard::hasNoSellValue);
|
||||
}
|
||||
if (showAutoSellCards) {
|
||||
collectionPool.addAllFlat(AdventurePlayer.current().getAutoSellCards().toFlatList());
|
||||
@@ -1120,12 +1120,13 @@ public class AdventureDeckEditor extends TabPageScreen<AdventureDeckEditor> {
|
||||
if (showCollectionCards) {
|
||||
adventurePool.addAll(AdventurePlayer.current().getCollectionCards(false));
|
||||
}
|
||||
if (showNoSellCards) {
|
||||
adventurePool.addAll(AdventurePlayer.current().getNoSellCards());
|
||||
adventurePool.removeAll(cardsInUse);
|
||||
} else {
|
||||
cardsInUse.removeAll(AdventurePlayer.current().getNoSellCards());
|
||||
adventurePool.removeAll(cardsInUse);
|
||||
else if(showNoSellCards) {
|
||||
adventurePool.addAll(AdventurePlayer.current().getCollectionCards(false).getFilteredPool(PaperCard::hasNoSellValue));
|
||||
}
|
||||
|
||||
adventurePool.removeAll(cardsInUse);
|
||||
if (!showNoSellCards) {
|
||||
adventurePool.removeIf(PaperCard::hasNoSellValue);
|
||||
}
|
||||
if (showAutoSellCards) {
|
||||
adventurePool.addAll(AdventurePlayer.current().getAutoSellCards());
|
||||
|
||||
@@ -223,7 +223,6 @@ public class ConsoleCommandInterpreter {
|
||||
PaperCard card = StaticData.instance().getCommonCards().getCard(s[0]);
|
||||
if (card == null) return "Cannot find card: " + s[0];
|
||||
Current.player().addCard(card.getNoSellVersion());
|
||||
Current.player().noSellCards.add(card.getNoSellVersion());
|
||||
return "Added card: " + s[0];
|
||||
});
|
||||
registerCommand(new String[]{"give", "item"}, s -> {
|
||||
|
||||
@@ -356,7 +356,7 @@ public class Config {
|
||||
final List<String> lines = FileUtil.readAllLines(new InputStreamReader(fileInputStream, Charset.forName(CardStorageReader.DEFAULT_CHARSET_NAME)), true);
|
||||
CardRules rules = rulesReader.readCard(lines, com.google.common.io.Files.getNameWithoutExtension(cardFile.getName()));
|
||||
rules.setCustom();
|
||||
PaperCard card = new PaperCard(rules, CardEdition.UNKNOWN.getCode(), CardRarity.Special) {
|
||||
PaperCard card = new PaperCard(rules, CardEdition.UNKNOWN_CODE, CardRarity.Special) {
|
||||
@Override
|
||||
public String getImageKey(boolean altState) {
|
||||
return ImageKeys.ADVENTURECARD_PREFIX + getName();
|
||||
|
||||
@@ -44,6 +44,8 @@ public class Reward {
|
||||
this.card = card;
|
||||
count = 0;
|
||||
this.isNoSell = isNoSell;
|
||||
if(isNoSell)
|
||||
this.card = card.getNoSellVersion();
|
||||
}
|
||||
|
||||
public Reward(Type type, int count) {
|
||||
@@ -60,6 +62,10 @@ public class Reward {
|
||||
this.deck = deck;
|
||||
count = 0;
|
||||
this.isNoSell = isNoSell;
|
||||
if(isNoSell)
|
||||
deck.getTags().add("noSell");
|
||||
//Could go through the deck and replace everything in it with the noSellValue version but the tag should
|
||||
//handle that later.
|
||||
}
|
||||
|
||||
public PaperCard getCard() {
|
||||
|
||||
@@ -1143,7 +1143,7 @@ public class CardImageRenderer {
|
||||
String set = state.getSetCode();
|
||||
CardRarity rarity = state.getRarity();
|
||||
if (!canShow) {
|
||||
set = CardEdition.UNKNOWN.getCode();
|
||||
set = CardEdition.UNKNOWN_CODE;
|
||||
rarity = CardRarity.Unknown;
|
||||
}
|
||||
if (!StringUtils.isEmpty(set)) {
|
||||
|
||||
@@ -9,6 +9,7 @@ import forge.Forge.KeyInputAdapter;
|
||||
import forge.Graphics;
|
||||
import forge.assets.*;
|
||||
import forge.card.CardEdition;
|
||||
import forge.card.ColorSet;
|
||||
import forge.card.MagicColor;
|
||||
import forge.deck.io.DeckPreferences;
|
||||
import forge.gamemodes.limited.BoosterDraft;
|
||||
@@ -1767,8 +1768,7 @@ public class FDeckEditor extends TabPageScreen<FDeckEditor> {
|
||||
CardManagerPage cardSourceSection;
|
||||
DeckSection destination = DeckSection.matchingSection(card);
|
||||
final DeckSectionPage destinationPage = parentScreen.getPageForSection(destination);
|
||||
// val for colorID setup
|
||||
int val;
|
||||
int markedColorCount = card.getRules().getSetColorID();
|
||||
switch (deckSection) {
|
||||
default:
|
||||
case Main:
|
||||
@@ -1811,14 +1811,18 @@ public class FDeckEditor extends TabPageScreen<FDeckEditor> {
|
||||
}
|
||||
}
|
||||
addCommanderItems(menu, card);
|
||||
if ((val = card.getRules().getSetColorID()) > 0) {
|
||||
if (markedColorCount > 0) {
|
||||
menu.addItem(new FMenuItem(Forge.getLocalizer().getMessage("lblColorIdentity"), Forge.hdbuttons ? FSkinImage.HDPREFERENCE : FSkinImage.SETTINGS, e -> {
|
||||
//sort options so current option is on top and selected by default
|
||||
Set<String> colorChoices = new HashSet<>(MagicColor.Constant.ONLY_COLORS);
|
||||
GuiChoose.getChoices(Forge.getLocalizer().getMessage("lblChooseAColor", Lang.getNumeral(val)), val, val, colorChoices, new Callback<>() {
|
||||
Set<String> currentColors;
|
||||
if(card.getMarkedColors() != null)
|
||||
currentColors = card.getMarkedColors().stream().map(MagicColor.Color::getName).collect(Collectors.toSet());
|
||||
else
|
||||
currentColors = null;
|
||||
String prompt = Forge.getLocalizer().getMessage("lblChooseAColor", Lang.getNumeral(markedColorCount));
|
||||
GuiChoose.getChoices(prompt, markedColorCount, markedColorCount, MagicColor.Constant.ONLY_COLORS, currentColors, null, new Callback<>() {
|
||||
@Override
|
||||
public void run(List<String> result) {
|
||||
addCard(card.getColorIDVersion(new HashSet<>(result)));
|
||||
addCard(card.copyWithMarkedColors(ColorSet.fromNames(result)));
|
||||
removeCard(card);
|
||||
}
|
||||
});
|
||||
@@ -1863,14 +1867,18 @@ public class FDeckEditor extends TabPageScreen<FDeckEditor> {
|
||||
}
|
||||
}
|
||||
addCommanderItems(menu, card);
|
||||
if ((val = card.getRules().getSetColorID()) > 0) {
|
||||
if (markedColorCount > 0) {
|
||||
menu.addItem(new FMenuItem(Forge.getLocalizer().getMessage("lblColorIdentity"), Forge.hdbuttons ? FSkinImage.HDPREFERENCE : FSkinImage.SETTINGS, e -> {
|
||||
//sort options so current option is on top and selected by default
|
||||
Set<String> colorChoices = new HashSet<>(MagicColor.Constant.ONLY_COLORS);
|
||||
GuiChoose.getChoices(Forge.getLocalizer().getMessage("lblChooseAColor", Lang.getNumeral(val)), val, val, colorChoices, new Callback<>() {
|
||||
Set<String> currentColors;
|
||||
if(card.getMarkedColors() != null)
|
||||
currentColors = card.getMarkedColors().stream().map(MagicColor.Color::getName).collect(Collectors.toSet());
|
||||
else
|
||||
currentColors = null;
|
||||
String prompt = Forge.getLocalizer().getMessage("lblChooseAColor", Lang.getNumeral(markedColorCount));
|
||||
GuiChoose.getChoices(prompt, markedColorCount, markedColorCount, MagicColor.Constant.ONLY_COLORS, currentColors, null, new Callback<>() {
|
||||
@Override
|
||||
public void run(List<String> result) {
|
||||
addCard(card.getColorIDVersion(new HashSet<>(result)));
|
||||
addCard(card.copyWithMarkedColors(ColorSet.fromNames(result)));
|
||||
removeCard(card);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -17,6 +17,7 @@ import forge.assets.*;
|
||||
import forge.assets.FSkinColor.Colors;
|
||||
import forge.card.*;
|
||||
import forge.card.CardRenderer.CardStackPosition;
|
||||
import forge.card.mana.ManaCostShard;
|
||||
import forge.deck.*;
|
||||
import forge.deck.io.DeckPreferences;
|
||||
import forge.game.card.CardView;
|
||||
@@ -34,11 +35,8 @@ import forge.util.ImageUtil;
|
||||
import forge.util.TextUtil;
|
||||
import forge.util.Utils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.*;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.TreeMap;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.IntStream;
|
||||
|
||||
@@ -980,7 +978,7 @@ public class ImageView<T extends InventoryItem> extends ItemView<T> {
|
||||
private boolean selected, deckSelectMode, showRanking;
|
||||
private final float IMAGE_SIZE = CardRenderer.MANA_SYMBOL_SIZE;
|
||||
private DeckProxy deckProxy = null;
|
||||
private String colorID = null;
|
||||
private String markedColors = null;
|
||||
private FImageComplex deckCover = null;
|
||||
private Texture dpImg = null;
|
||||
//private TextureRegion tr;
|
||||
@@ -1007,8 +1005,10 @@ public class ImageView<T extends InventoryItem> extends ItemView<T> {
|
||||
draftRankImage = FSkinImage.DRAFTRANK_C;
|
||||
}
|
||||
}
|
||||
if (((PaperCard) item).getColorID() != null) {
|
||||
colorID = ((PaperCard) item).getColorID().stream().map(MagicColor::toSymbol).collect(Collectors.joining());
|
||||
if (((PaperCard) item).getMarkedColors() != null) {
|
||||
markedColors = Arrays.stream(((PaperCard) item).getMarkedColors().getOrderedShards())
|
||||
.map(ManaCostShard::toString)
|
||||
.collect(Collectors.joining());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1082,7 +1082,7 @@ public class ImageView<T extends InventoryItem> extends ItemView<T> {
|
||||
cardPrice = ((ShopScene) Forge.getCurrentScene()).getCardPrice((PaperCard) item);
|
||||
drawCardLabel(g, "$" + cardPrice, Color.GOLD, x, y ,w ,h);
|
||||
} else {
|
||||
if (((PaperCard) item).isNoSell() && itemManager.showNFSWatermark() && !Config.instance().getSettingData().disableNotForSale) {
|
||||
if (((PaperCard) item).hasNoSellValue() && itemManager.showNFSWatermark() && !Config.instance().getSettingData().disableNotForSale) {
|
||||
Texture nfs = Forge.getAssets().getTexture(getDefaultSkinFile("nfs.png"), false);
|
||||
if (nfs != null)
|
||||
g.drawImage(nfs, x, y, w, h);
|
||||
@@ -1092,8 +1092,8 @@ public class ImageView<T extends InventoryItem> extends ItemView<T> {
|
||||
}
|
||||
}
|
||||
// spire colors
|
||||
if (colorID != null && !colorID.isEmpty()) {
|
||||
textRenderer.drawText(g, colorID, FSkinFont.forHeight(w / 5), Color.WHITE, x, y + h / 4, w, h, y, h, false, Align.center, true);
|
||||
if (markedColors != null && !markedColors.isEmpty()) {
|
||||
textRenderer.drawText(g, markedColors, FSkinFont.forHeight(w / 5), Color.WHITE, x, y + h / 4, w, h, y, h, false, Align.center, true);
|
||||
}
|
||||
} else if (item instanceof ConquestCommander) {
|
||||
CardRenderer.drawCard(g, ((ConquestCommander) item).getCard(), x, y, w, h, pos);
|
||||
|
||||
@@ -660,7 +660,7 @@ public class MatchController extends AbstractGuiGame {
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> List<T> getChoices(final String message, final int min, final int max, final List<T> choices, final T selected, final Function<T, String> display) {
|
||||
public <T> List<T> getChoices(final String message, final int min, final int max, final List<T> choices, final List<T> selected, final Function<T, String> display) {
|
||||
return GuiBase.getInterface().getChoices(message, min, max, choices, selected, display);
|
||||
}
|
||||
|
||||
|
||||
@@ -355,7 +355,7 @@ public class ConquestAEtherScreen extends FScreen {
|
||||
caption = caption0;
|
||||
options = ImmutableList.copyOf(options0);
|
||||
setSelectedOption(options.get(0));
|
||||
setCommand(e -> GuiChoose.getChoices(Forge.getLocalizer().getMessage("lblSelectCaptionFilter", caption), 0, 1, options, selectedOption, null, new Callback<List<AEtherFilter>>() {
|
||||
setCommand(e -> GuiChoose.getChoices(Forge.getLocalizer().getMessage("lblSelectCaptionFilter", caption), 0, 1, options, Set.of(selectedOption), null, new Callback<>() {
|
||||
@Override
|
||||
public void run(List<AEtherFilter> result) {
|
||||
if (!result.isEmpty()) {
|
||||
|
||||
@@ -3,6 +3,7 @@ package forge.toolbox;
|
||||
import static forge.card.CardRenderer.MANA_SYMBOL_SIZE;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
@@ -271,6 +272,14 @@ public class FChoiceList<T> extends FList<T> implements ActivateHandler {
|
||||
setSelectedIndex(getIndexOf(choice));
|
||||
}
|
||||
|
||||
public void setSelectedItems(Collection<T> items) {
|
||||
selectedIndices.clear();
|
||||
items.stream().mapToInt(this::getIndexOf).filter(i -> i >= 0).forEach(selectedIndices::add);
|
||||
if(!items.isEmpty())
|
||||
scrollIntoView(getIndexOf(items.iterator().next()));
|
||||
onSelectionChange();
|
||||
}
|
||||
|
||||
protected String getChoiceText(T choice) {
|
||||
return choice.toString();
|
||||
}
|
||||
|
||||
@@ -230,7 +230,7 @@ public class GuiChoose {
|
||||
getChoices(message, min, max, choices, null, null, callback);
|
||||
}
|
||||
|
||||
public static <T> void getChoices(final String message, final int min, final int max, final Collection<T> choices, final T selected, final Function<T, String> display, final Callback<List<T>> callback) {
|
||||
public static <T> void getChoices(final String message, final int min, final int max, final Collection<T> choices, final Collection<T> selected, final Function<T, String> display, final Callback<List<T>> callback) {
|
||||
if (choices == null || choices.isEmpty()) {
|
||||
if (min == 0) {
|
||||
callback.run(new ArrayList<>());
|
||||
|
||||
@@ -201,11 +201,8 @@ public class ListChooser<T> extends FContainer {
|
||||
|
||||
/**
|
||||
* Shows the dialog and returns after the dialog was closed.
|
||||
*
|
||||
* @param index0 index to select when shown
|
||||
* @return a boolean.
|
||||
*/
|
||||
public void show(final T item, final boolean selectMax) {
|
||||
public void show(final Collection<T> item, final boolean selectMax) {
|
||||
if (called) {
|
||||
throw new IllegalStateException("Already shown");
|
||||
}
|
||||
@@ -226,7 +223,7 @@ public class ListChooser<T> extends FContainer {
|
||||
}
|
||||
}
|
||||
else {
|
||||
lstChoices.setSelectedItem(item);
|
||||
lstChoices.setSelectedItems(item);
|
||||
}
|
||||
optionPane.show();
|
||||
}
|
||||
|
||||
@@ -3462,7 +3462,7 @@ AdvBossIntro34=Es gibt kein Zurück!
|
||||
AdvBossIntro35=Jetzt geht es um alles oder nichts!
|
||||
lblYouDied={0}, du bist gestorben!!!
|
||||
lblSellFor=Verkaufen für
|
||||
lblUnsellableCount=Unverkäuflich ({0})
|
||||
lblUnsellable=Unverkäuflich
|
||||
lblAutoSell=AUTOVERKAUF
|
||||
lblNoSell=NICHT VERKAUFEN
|
||||
lbltoSell=Zu verkaufen ({0}/{1})
|
||||
|
||||
@@ -3210,7 +3210,7 @@ AdvBossIntro34=There's no turning back!
|
||||
AdvBossIntro35=It's all or nothing now!
|
||||
lblYouDied={0}, You Died!!!
|
||||
lblSellFor=Sell for
|
||||
lblUnsellableCount=Unsellable ({0})
|
||||
lblUnsellable=Unsellable
|
||||
lblAutoSell=AUTO-SELL
|
||||
lblNoSell=NO-SELL
|
||||
lbltoSell=To Sell ({0}/{1})
|
||||
|
||||
@@ -3473,7 +3473,7 @@ AdvBossIntro34=¡No hay marcha atrás!
|
||||
AdvBossIntro35=¡Ahora es todo o nada!
|
||||
lblYouDied={0}, ¡¡¡Moriste!!!
|
||||
lblSellFor=Vender por
|
||||
lblUnsellableCount=No vendible ({0})
|
||||
lblUnsellable=No vendible
|
||||
lblAutoSell=AUTOVENTA
|
||||
lblNoSell=NO VENDER
|
||||
lbltoSell=Para vender ({0}/{1})
|
||||
|
||||
@@ -3467,7 +3467,7 @@ AdvBossIntro34=Il n'y a pas de retour en arrière!
|
||||
AdvBossIntro35=C'est tout ou rien maintenant !
|
||||
lblYouDied={0}, tu es mort !!!
|
||||
lblSellFor=Vendre pour
|
||||
lblUnsellableCount=Invendable ({0})
|
||||
lblUnsellable=Invendable
|
||||
lblAutoSell=VENTE AUTOMATIQUE
|
||||
lblNoSell=NON-VENTE
|
||||
lbltoSell=À vendre ({0}/{1})
|
||||
|
||||
@@ -3465,7 +3465,7 @@ AdvBossIntro34=Non si può tornare indietro!
|
||||
AdvBossIntro35=Adesso è tutto o niente!
|
||||
lblYouDied={0}, sei morto!!!
|
||||
lblSellFor=Vendi per
|
||||
lblUnsellableCount=Invendibile ({0})
|
||||
lblUnsellable=Invendibile
|
||||
lblAutoSell=AUTOVENDITA
|
||||
lblNoSell=NON VENDITA
|
||||
lbltoSell=Da vendere ({0}/{1})
|
||||
|
||||
@@ -3461,7 +3461,7 @@ AdvBossIntro34=もう後戻りはできない!
|
||||
AdvBossIntro35=もう、オール・オア・ナッシングだ!
|
||||
lblYouDied={0}、死んだ!!!
|
||||
lblSellFor=で売る
|
||||
lblUnsellableCount=販売不可 ({0})
|
||||
lblUnsellable=販売不可
|
||||
lblAutoSell=自動販売
|
||||
lblNoSell=販売禁止
|
||||
lbltoSell=販売する ({0}/{1})
|
||||
|
||||
@@ -3551,7 +3551,7 @@ AdvBossIntro34=Não há como voltar atrás!
|
||||
AdvBossIntro35=É tudo ou nada agora!
|
||||
lblYouDied={0}, você morreu!!!
|
||||
lblSellFor=Vender por
|
||||
lblUnsellableCount=Invendável ({0})
|
||||
lblUnsellable=Invendável
|
||||
lblAutoSell=VENDA AUTOMÁTICA
|
||||
lblNoSell=NÃO VENDER
|
||||
lbltoSell=Para Vender ({0}/{1})
|
||||
|
||||
@@ -3452,7 +3452,7 @@ AdvBossIntro34=没有回头路了!
|
||||
AdvBossIntro35=现在要么全有要么全无!
|
||||
lblYouDied={0},你死了!!!
|
||||
lblSellFor=售价为
|
||||
lblUnsellableCount=无法出售({0})
|
||||
lblUnsellable=无法出售
|
||||
lblAutoSell=自动销售
|
||||
lblNoSell=不卖
|
||||
lbltoSell=出售({0}/{1})
|
||||
|
||||
@@ -64,7 +64,7 @@ public enum ProtocolMethod {
|
||||
showOptionDialog (Mode.SERVER, Integer.TYPE, String.class, String.class, FSkinProp.class, List/*String*/.class, Integer.TYPE),
|
||||
showInputDialog (Mode.SERVER, String.class, String.class, String.class, FSkinProp.class, String.class, List/*String*/.class, Boolean.TYPE),
|
||||
confirm (Mode.SERVER, Boolean.TYPE, CardView.class, String.class, Boolean.TYPE, List/*String*/.class),
|
||||
getChoices (Mode.SERVER, List.class, String.class, Integer.TYPE, Integer.TYPE, List.class, Object.class, Function.class),
|
||||
getChoices (Mode.SERVER, List.class, String.class, Integer.TYPE, Integer.TYPE, List.class, List.class, Function.class),
|
||||
order (Mode.SERVER, List.class, String.class, String.class, Integer.TYPE, Integer.TYPE, List.class, List.class, CardView.class, Boolean.TYPE),
|
||||
sideboard (Mode.SERVER, List.class, CardPool.class, CardPool.class, String.class),
|
||||
chooseSingleEntityForEffect(Mode.SERVER, GameEntityView.class, String.class, List.class, DelayedReveal.class, Boolean.TYPE),
|
||||
|
||||
@@ -246,7 +246,7 @@ public class NetGuiGame extends AbstractGuiGame {
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> List<T> getChoices(final String message, final int min, final int max, final List<T> choices, final T selected, final Function<T, String> display) {
|
||||
public <T> List<T> getChoices(final String message, final int min, final int max, final List<T> choices, final List<T> selected, final Function<T, String> display) {
|
||||
return sendAndWait(ProtocolMethod.getChoices, message, min, max, choices, selected, display);
|
||||
}
|
||||
|
||||
|
||||
@@ -32,6 +32,7 @@ import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map.Entry;
|
||||
@@ -510,11 +511,11 @@ public class QuestWinLoseController {
|
||||
final List<GameFormat> formats = new ArrayList<>();
|
||||
final String preferredFormat = FModel.getQuestPreferences().getPref(QPref.BOOSTER_FORMAT);
|
||||
|
||||
GameFormat pref = null;
|
||||
Collection<GameFormat> pref = null;
|
||||
for (final GameFormat f : FModel.getFormats().getSanctionedList()) {
|
||||
formats.add(f);
|
||||
if (f.toString().equals(preferredFormat)) {
|
||||
pref = f;
|
||||
pref = List.of(f);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -129,7 +129,7 @@ public class CardDetailUtil {
|
||||
}
|
||||
|
||||
public static String getCurrentColors(final CardStateView c) {
|
||||
return c.getColors().toEnumSet().stream().map(MagicColor.Color::getSymbol).collect(Collectors.joining());
|
||||
return c.getColors().stream().map(MagicColor.Color::getSymbol).collect(Collectors.joining());
|
||||
}
|
||||
|
||||
public static DetailColors getRarityColor(final CardRarity rarity) {
|
||||
@@ -450,10 +450,10 @@ public class CardDetailUtil {
|
||||
}
|
||||
|
||||
// chosen spire
|
||||
if (card.getChosenColorID() != null && !card.getChosenColorID().isEmpty()) {
|
||||
if (card.getMarkedColors() != null && !card.getMarkedColors().isColorless()) {
|
||||
area.append("\n");
|
||||
area.append("(").append(Localizer.getInstance().getMessage("lblSelected")).append(": ");
|
||||
area.append(Lang.joinHomogenous(card.getChosenColorID().stream().map(DeckRecognizer::getLocalisedMagicColorName).collect(Collectors.toList())));
|
||||
area.append(Lang.joinHomogenous(card.getMarkedColors().stream().map(MagicColor.Color::getLocalizedName).collect(Collectors.toList())));
|
||||
area.append(")");
|
||||
}
|
||||
|
||||
|
||||
@@ -55,7 +55,7 @@ public class GuiDownloadSetPicturesLQ extends GuiDownloadService {
|
||||
}
|
||||
final String setCode2 = setMapping.get(setCode3);
|
||||
|
||||
if (StringUtils.isBlank(setCode3) || CardEdition.UNKNOWN.getCode().equals(setCode3)) {
|
||||
if (StringUtils.isBlank(setCode3) || CardEdition.UNKNOWN_CODE.equals(setCode3)) {
|
||||
// we don't want cards from unknown sets
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -38,7 +38,7 @@ public interface IGuiBase {
|
||||
void showImageDialog(ISkinImage image, String message, String title);
|
||||
int showOptionDialog(String message, String title, FSkinProp icon, List<String> options, int defaultOption);
|
||||
String showInputDialog(String message, String title, FSkinProp icon, String initialInput, List<String> inputOptions, boolean isNumeric);
|
||||
<T> List<T> getChoices(String message, int min, int max, Collection<T> choices, T selected, Function<T, String> display);
|
||||
<T> List<T> getChoices(String message, int min, int max, Collection<T> choices, Collection<T> selected, Function<T, String> display);
|
||||
<T> List<T> order(String title, String top, int remainingObjectsMin, int remainingObjectsMax, List<T> sourceChoices, List<T> destChoices);
|
||||
String showFileDialog(String title, String defaultDir);
|
||||
File getSaveFile(File defaultFile);
|
||||
|
||||
@@ -150,7 +150,7 @@ public interface IGuiGame {
|
||||
|
||||
<T> List<T> getChoices(String message, int min, int max, List<T> choices);
|
||||
|
||||
<T> List<T> getChoices(String message, int min, int max, List<T> choices, T selected, Function<T, String> display);
|
||||
<T> List<T> getChoices(String message, int min, int max, List<T> choices, List<T> selected, Function<T, String> display);
|
||||
|
||||
// Get Integer in range
|
||||
Integer getInteger(String message, int min);
|
||||
|
||||
@@ -43,7 +43,7 @@ public class SGuiChoose {
|
||||
if ((choices == null) || choices.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
final List<T> choice = SGuiChoose.getChoices(message, 0, 1, choices, selected, display);
|
||||
final List<T> choice = SGuiChoose.getChoices(message, 0, 1, choices, selected == null ? null : List.of(selected), display);
|
||||
return choice.isEmpty() ? null : choice.get(0);
|
||||
}
|
||||
|
||||
@@ -147,12 +147,12 @@ public class SGuiChoose {
|
||||
return getChoices(message, min, max, Arrays.asList(choices), null, null);
|
||||
}
|
||||
public static <T> List<T> getChoices(final String message, final int min, final int max, final T[] choices, final T selected, final Function<T, String> display) {
|
||||
return getChoices(message, min, max, Arrays.asList(choices), selected, display);
|
||||
return getChoices(message, min, max, Arrays.asList(choices), selected == null ? null : List.of(selected), display);
|
||||
}
|
||||
public static <T> List<T> getChoices(final String message, final int min, final int max, final Collection<T> choices) {
|
||||
return getChoices(message, min, max, choices, null, null);
|
||||
}
|
||||
public static <T> List<T> getChoices(final String message, final int min, final int max, final Collection<T> choices, final T selected, final Function<T, String> display) {
|
||||
public static <T> List<T> getChoices(final String message, final int min, final int max, final Collection<T> choices, final Collection<T> selected, final Function<T, String> display) {
|
||||
return GuiBase.getInterface().getChoices(message, min, max, choices, selected, display);
|
||||
}
|
||||
|
||||
|
||||
@@ -54,7 +54,7 @@ public enum ColumnDef {
|
||||
NAME("lblName", "lblName", 180, false, SortState.ASC,
|
||||
from -> {
|
||||
if (from.getKey() instanceof PaperCard) {
|
||||
String spire = ((PaperCard) from.getKey()).getColorID() == null ? "" : ((PaperCard) from.getKey()).getColorID().toString();
|
||||
String spire = ((PaperCard) from.getKey()).getMarkedColors() == null ? "" : ((PaperCard) from.getKey()).getMarkedColors().toString();
|
||||
String sortableName = ((PaperCard)from.getKey()).getSortableName();
|
||||
return sortableName == null ? TextUtil.toSortableName(from.getKey().getName() + spire) : sortableName + spire;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user