Merge branch 'master' into AI_ATTACK_TIMEOUT

This commit is contained in:
kevlahnota
2024-11-16 18:52:12 +08:00
committed by GitHub
23 changed files with 271 additions and 30 deletions

View File

@@ -43,6 +43,7 @@ import java.util.stream.Collectors;
public final class CardDb implements ICardDatabase, IDeckGenPool { public final class CardDb implements ICardDatabase, IDeckGenPool {
public final static String foilSuffix = "+"; public final static String foilSuffix = "+";
public final static char NameSetSeparator = '|'; public final static char NameSetSeparator = '|';
public final static String colorIDPrefix = "#";
private final String exlcudedCardName = "Concentrate"; private final String exlcudedCardName = "Concentrate";
private final String exlcudedCardSet = "DS0"; private final String exlcudedCardSet = "DS0";
@@ -91,13 +92,19 @@ public final class CardDb implements ICardDatabase, IDeckGenPool {
public int artIndex; public int artIndex;
public boolean isFoil; public boolean isFoil;
public String collectorNumber; public String collectorNumber;
public Set<String> colorID;
private CardRequest(String name, String edition, int artIndex, boolean isFoil, String collectorNumber) { 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) {
cardName = name; cardName = name;
this.edition = edition; this.edition = edition;
this.artIndex = artIndex; this.artIndex = artIndex;
this.isFoil = isFoil; this.isFoil = isFoil;
this.collectorNumber = collectorNumber; this.collectorNumber = collectorNumber;
this.colorID = colorID;
} }
public static boolean isFoilCardName(final String cardName){ public static boolean isFoilCardName(final String cardName){
@@ -126,6 +133,14 @@ public final class CardDb implements ICardDatabase, IDeckGenPool {
return requestInfo + NameSetSeparator + artIndex; 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) { public static String compose(String cardName, String setCode, String collectorNumber) {
String requestInfo = compose(cardName, setCode); String requestInfo = compose(cardName, setCode);
// CollectorNumber will be wrapped in square brackets // CollectorNumber will be wrapped in square brackets
@@ -155,6 +170,10 @@ public final class CardDb implements ICardDatabase, IDeckGenPool {
return s.startsWith("[") && s.endsWith("]"); return s.startsWith("[") && s.endsWith("]");
} }
private static boolean isColorIDString(String s) {
return s.startsWith(colorIDPrefix);
}
private static boolean isArtIndex(String s) { private static boolean isArtIndex(String s) {
return StringUtils.isNumeric(s) && s.length() <= 2 ; // only artIndex between 1-99 return StringUtils.isNumeric(s) && s.length() <= 2 ; // only artIndex between 1-99
} }
@@ -172,7 +191,7 @@ public final class CardDb implements ICardDatabase, IDeckGenPool {
String cardName = info[0]; String cardName = info[0];
String setCode = info[1]; String setCode = info[1];
int artIndex = Integer.parseInt(info[2]); int artIndex = Integer.parseInt(info[2]);
return new CardRequest(cardName, setCode, artIndex, isFoil, IPaperCard.NO_COLLECTOR_NUMBER); return new CardRequest(cardName, setCode, artIndex, isFoil, IPaperCard.NO_COLLECTOR_NUMBER, null);
} catch (NumberFormatException ex){ return null; } } catch (NumberFormatException ex){ return null; }
} }
@@ -184,22 +203,29 @@ public final class CardDb implements ICardDatabase, IDeckGenPool {
int setPos; int setPos;
int artPos; int artPos;
int cNrPos; int cNrPos;
int clrPos;
if (info.length >= 4) { // name|set|artIndex|[collNr] if (info.length >= 4) { // name|set|artIndex|[collNr]
setPos = isSetCode(info[1]) ? 1 : -1; setPos = isSetCode(info[1]) ? 1 : -1;
artPos = isArtIndex(info[2]) ? 2 : -1; artPos = isArtIndex(info[2]) ? 2 : -1;
cNrPos = isCollectorNumber(info[3]) ? 3 : -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) } else if (info.length == 3) { // name|set|artIndex (or CollNr)
setPos = isSetCode(info[1]) ? 1 : -1; setPos = isSetCode(info[1]) ? 1 : -1;
artPos = isArtIndex(info[2]) ? 2 : -1; artPos = isArtIndex(info[2]) ? 2 : -1;
cNrPos = isCollectorNumber(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) } else if (info.length == 2) { // name|set (or artIndex, even if not possible via compose)
setPos = isSetCode(info[1]) ? 1 : -1; setPos = isSetCode(info[1]) ? 1 : -1;
artPos = isArtIndex(info[1]) ? 1 : -1; artPos = isArtIndex(info[1]) ? 1 : -1;
cNrPos = -1; cNrPos = -1;
clrPos = -1;
} else { } else {
setPos = -1; setPos = -1;
artPos = -1; artPos = -1;
cNrPos = -1; cNrPos = -1;
clrPos = -1;
} }
String cardName = info[0]; String cardName = info[0];
boolean isFoil = false; boolean isFoil = false;
@@ -210,6 +236,7 @@ public final class CardDb implements ICardDatabase, IDeckGenPool {
int artIndex = artPos > 0 ? Integer.parseInt(info[artPos]) : IPaperCard.NO_ART_INDEX; // default: no art index 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 collectorNumber = cNrPos > 0 ? info[cNrPos].substring(1, info[cNrPos].length() - 1) : IPaperCard.NO_COLLECTOR_NUMBER;
String setCode = setPos > 0 ? info[setPos] : null; 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 (setCode != null && setCode.equals(CardEdition.UNKNOWN.getCode())) { // ???
setCode = null; setCode = null;
} }
@@ -225,7 +252,7 @@ public final class CardDb implements ICardDatabase, IDeckGenPool {
// finally, check whether any between artIndex and CollectorNumber has been set // finally, check whether any between artIndex and CollectorNumber has been set
if (collectorNumber.equals(IPaperCard.NO_COLLECTOR_NUMBER) && artIndex == IPaperCard.NO_ART_INDEX) if (collectorNumber.equals(IPaperCard.NO_COLLECTOR_NUMBER) && artIndex == IPaperCard.NO_ART_INDEX)
artIndex = IPaperCard.DEFAULT_ART_INDEX; artIndex = IPaperCard.DEFAULT_ART_INDEX;
return new CardRequest(cardName, setCode, artIndex, isFoil, collectorNumber); return new CardRequest(cardName, setCode, artIndex, isFoil, collectorNumber, colorID);
} }
} }
@@ -570,6 +597,13 @@ public final class CardDb implements ICardDatabase, IDeckGenPool {
return tryGetCard(request); 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);
CardRequest request = CardRequest.fromString(reqInfo);
return tryGetCard(request);
}
private PaperCard tryGetCard(CardRequest request) { private PaperCard tryGetCard(CardRequest request) {
// Before doing anything, check that a non-null request has been provided // Before doing anything, check that a non-null request has been provided
if (request == null) if (request == null)
@@ -581,8 +615,9 @@ public final class CardDb implements ICardDatabase, IDeckGenPool {
// MOST of the extensions have two short codes, 141 out of 221 (so far) // MOST of the extensions have two short codes, 141 out of 221 (so far)
// ALSO: Set Code are always UpperCase // ALSO: Set Code are always UpperCase
CardEdition edition = editions.get(reqEditionCode.toUpperCase()); CardEdition edition = editions.get(reqEditionCode.toUpperCase());
return this.getCardFromSet(request.cardName, edition, request.artIndex, return this.getCardFromSet(request.cardName, edition, request.artIndex,
request.collectorNumber, request.isFoil); request.collectorNumber, request.isFoil, request.colorID);
} }
// 2. Card lookup in edition with specified filter didn't work. // 2. Card lookup in edition with specified filter didn't work.
@@ -624,8 +659,12 @@ public final class CardDb implements ICardDatabase, IDeckGenPool {
} }
@Override @Override
public PaperCard getCardFromSet(String cardName, CardEdition edition, int artIndex, public PaperCard getCardFromSet(String cardName, CardEdition edition, int artIndex, String collectorNumber, boolean isFoil) {
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 if (edition == null || cardName == null) // preview cards
return null; // No cards will be returned return null; // No cards will be returned
@@ -659,7 +698,7 @@ public final class CardDb implements ICardDatabase, IDeckGenPool {
while (!candidate.hasImage() && candidatesIterator.hasNext()) while (!candidate.hasImage() && candidatesIterator.hasNext())
candidate = candidatesIterator.next(); candidate = candidatesIterator.next();
candidate = candidate.hasImage() ? candidate : firstCandidate; candidate = candidate.hasImage() ? candidate : firstCandidate;
return isFoil ? candidate.getFoiled() : candidate; return isFoil ? candidate.getFoiled().getColorIDVersion(colorID) : candidate.getColorIDVersion(colorID);
} }
/* /*
@@ -702,6 +741,11 @@ public final class CardDb implements ICardDatabase, IDeckGenPool {
return this.tryToGetCardFromEditions(cardInfo, artPreference, artIndex, filter); 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 * 4. SPECIALISED CARD LOOKUP BASED ON
@@ -776,6 +820,11 @@ public final class CardDb implements ICardDatabase, IDeckGenPool {
private PaperCard tryToGetCardFromEditions(String cardInfo, CardArtPreference artPreference, int artIndex, private PaperCard tryToGetCardFromEditions(String cardInfo, CardArtPreference artPreference, int artIndex,
Date releaseDate, boolean releasedBeforeFlag, Predicate<PaperCard> filter){ 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){
if (cardInfo == null) if (cardInfo == null)
return null; return null;
final CardRequest cr = CardRequest.fromString(cardInfo); final CardRequest cr = CardRequest.fromString(cardInfo);
@@ -856,7 +905,7 @@ public final class CardDb implements ICardDatabase, IDeckGenPool {
} }
candidate = candidate.hasImage() ? candidate : firstCandidate; candidate = candidate.hasImage() ? candidate : firstCandidate;
//If any, we're sure that at least one candidate is always returned despite it having any image //If any, we're sure that at least one candidate is always returned despite it having any image
return cr.isFoil ? candidate.getFoiled() : candidate; return cr.isFoil ? candidate.getFoiled().getColorIDVersion(colorID) : candidate.getColorIDVersion(colorID);
} }
@Override @Override
@@ -1129,6 +1178,11 @@ public final class CardDb implements ICardDatabase, IDeckGenPool {
if (artCount >= IPaperCard.DEFAULT_ART_INDEX) { if (artCount >= IPaperCard.DEFAULT_ART_INDEX) {
sb.append(CardDb.NameSetSeparator).append(card.getArtIndex()); // indexes start at 1 to match image file name conventions 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; return sb;

View File

@@ -53,6 +53,7 @@ public final class CardRules implements ICardCharacteristics {
private String meldWith; private String meldWith;
private String partnerWith; private String partnerWith;
private boolean addsWildCardColor; private boolean addsWildCardColor;
private int setColorID;
private boolean custom; private boolean custom;
public CardRules(ICardFace[] faces, CardSplitType altMode, CardAiHints cah) { public CardRules(ICardFace[] faces, CardSplitType altMode, CardAiHints cah) {
@@ -72,6 +73,8 @@ public final class CardRules implements ICardCharacteristics {
meldWith = ""; meldWith = "";
partnerWith = ""; partnerWith = "";
addsWildCardColor = false; addsWildCardColor = false;
setColorID = 0;
//calculate color identity //calculate color identity
byte colMask = calculateColorIdentity(mainPart); byte colMask = calculateColorIdentity(mainPart);
@@ -95,6 +98,7 @@ public final class CardRules implements ICardCharacteristics {
meldWith = newRules.meldWith; meldWith = newRules.meldWith;
partnerWith = newRules.partnerWith; partnerWith = newRules.partnerWith;
addsWildCardColor = newRules.addsWildCardColor; addsWildCardColor = newRules.addsWildCardColor;
setColorID = newRules.setColorID;
tokens = newRules.tokens; tokens = newRules.tokens;
} }
@@ -397,6 +401,10 @@ public final class CardRules implements ICardCharacteristics {
return addsWildCardColor; return addsWildCardColor;
} }
public int getSetColorID() {
return setColorID;
}
// vanguard card fields, they don't use sides. // vanguard card fields, they don't use sides.
private int deltaHand; private int deltaHand;
private int deltaLife; private int deltaLife;
@@ -448,6 +456,7 @@ public final class CardRules implements ICardCharacteristics {
private String meldWith = ""; private String meldWith = "";
private String partnerWith = ""; private String partnerWith = "";
private boolean addsWildCardColor = false; private boolean addsWildCardColor = false;
private int setColorID = 0;
private String handLife = null; private String handLife = null;
private String normalizedName = ""; private String normalizedName = "";
private Set<String> supportedFunctionalVariants = null; private Set<String> supportedFunctionalVariants = null;
@@ -512,6 +521,7 @@ public final class CardRules implements ICardCharacteristics {
result.meldWith = this.meldWith; result.meldWith = this.meldWith;
result.partnerWith = this.partnerWith; result.partnerWith = this.partnerWith;
result.addsWildCardColor = this.addsWildCardColor; result.addsWildCardColor = this.addsWildCardColor;
result.setColorID = this.setColorID;
if (!tokens.isEmpty()) { if (!tokens.isEmpty()) {
result.tokens = tokens; result.tokens = tokens;
} }
@@ -687,6 +697,8 @@ public final class CardRules implements ICardCharacteristics {
value = colonPos > 0 ? value.substring(1+colonPos) : null; value = colonPos > 0 ? value.substring(1+colonPos) : null;
face.addSVar(variable, value); face.addSVar(variable, value);
} else if (key.startsWith("SETCOLORID")) {
this.setColorID = Integer.parseInt(value);
} }
break; break;

View File

@@ -7,6 +7,7 @@ import forge.item.PaperCard;
import java.util.Collection; import java.util.Collection;
import java.util.Date; import java.util.Date;
import java.util.List; import java.util.List;
import java.util.Set;
public interface ICardDatabase extends Iterable<PaperCard> { public interface ICardDatabase extends Iterable<PaperCard> {
/** /**
@@ -50,18 +51,21 @@ public interface ICardDatabase extends Iterable<PaperCard> {
// [NEW Methods] Including the card CollectorNumber as criterion for DB lookup // [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, String collectorNumber);
PaperCard getCard(String cardName, String edition, int artIndex, String collectorNumber); PaperCard getCard(String cardName, String edition, int artIndex, String collectorNumber);
PaperCard getCard(String cardName, String edition, int artIndex, Set<String> colorID);
// 2. Card Lookup from a single Expansion Set // 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, 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, String collectorNumber, boolean isFoil);
PaperCard getCardFromSet(String cardName, CardEdition edition, int artIndex, 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);
PaperCard getCardFromSet(String cardName, CardEdition edition, int artIndex, String collectorNumber, boolean isFoil, Set<String> colorID);
// 3. Card lookup based on CardArtPreference Selection Policy // 3. Card lookup based on CardArtPreference Selection Policy
PaperCard getCardFromEditions(String cardName, CardArtPreference artPreference); PaperCard getCardFromEditions(String cardName, CardArtPreference artPreference);
PaperCard getCardFromEditions(String cardName, CardArtPreference artPreference, Predicate<PaperCard> filter); 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);
PaperCard getCardFromEditions(String cardName, CardArtPreference artPreference, int artIndex, Predicate<PaperCard> filter); 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 // 4. Specialised Card Lookup on CardArtPreference Selection and Release Date
PaperCard getCardFromEditionsReleasedBefore(String cardName, CardArtPreference artPreference, Date releaseDate); PaperCard getCardFromEditionsReleasedBefore(String cardName, CardArtPreference artPreference, Date releaseDate);

View File

@@ -54,7 +54,7 @@ public class CardPool extends ItemPool<PaperCard> {
public void add(final String cardRequest, final int amount) { public void add(final String cardRequest, final int amount) {
CardDb.CardRequest request = CardDb.CardRequest.fromString(cardRequest); CardDb.CardRequest request = CardDb.CardRequest.fromString(cardRequest);
this.add(CardDb.CardRequest.compose(request.cardName, request.isFoil), request.edition, request.artIndex, amount); this.add(CardDb.CardRequest.compose(request.cardName, request.isFoil), request.edition, request.artIndex, amount, false, request.colorID);
} }
public void add(final String cardName, final String setCode) { public void add(final String cardName, final String setCode) {
@@ -66,14 +66,14 @@ public class CardPool extends ItemPool<PaperCard> {
} }
public void add(final String cardName, final String setCode, final int amount, boolean addAny) { public void add(final String cardName, final String setCode, final int amount, boolean addAny) {
this.add(cardName, setCode, IPaperCard.NO_ART_INDEX, amount, addAny); this.add(cardName, setCode, IPaperCard.NO_ART_INDEX, amount, addAny, null);
} }
// NOTE: ART indices are "1" -based // NOTE: ART indices are "1" -based
public void add(String cardName, String setCode, int artIndex, final int amount) { public void add(String cardName, String setCode, int artIndex, final int amount) {
this.add(cardName, setCode, artIndex, amount, false); this.add(cardName, setCode, artIndex, amount, false, null);
} }
public void add(String cardName, String setCode, int artIndex, final int amount, boolean addAny) { public void add(String cardName, String setCode, int artIndex, final int amount, boolean addAny, Set<String> colorID) {
Map<String, CardDb> dbs = StaticData.instance().getAvailableDatabases(); Map<String, CardDb> dbs = StaticData.instance().getAvailableDatabases();
PaperCard paperCard = null; PaperCard paperCard = null;
String selectedDbName = ""; String selectedDbName = "";
@@ -83,7 +83,7 @@ public class CardPool extends ItemPool<PaperCard> {
for (Map.Entry<String, CardDb> entry: dbs.entrySet()){ for (Map.Entry<String, CardDb> entry: dbs.entrySet()){
String dbName = entry.getKey(); String dbName = entry.getKey();
CardDb db = entry.getValue(); CardDb db = entry.getValue();
paperCard = db.getCard(cardName, setCode, artIndex); paperCard = db.getCard(cardName, setCode, artIndex, colorID);
if (paperCard != null) { if (paperCard != null) {
selectedDbName = dbName; selectedDbName = dbName;
break; break;
@@ -125,7 +125,7 @@ public class CardPool extends ItemPool<PaperCard> {
int cnt = artGroups[i - 1]; int cnt = artGroups[i - 1];
if (cnt <= 0) if (cnt <= 0)
continue; continue;
PaperCard randomCard = cardDb.getCard(cardName, setCode, i); PaperCard randomCard = cardDb.getCard(cardName, setCode, i, colorID);
this.add(randomCard, cnt); this.add(randomCard, cnt);
} }
} }

View File

@@ -337,7 +337,7 @@ public class Deck extends DeckBase implements Iterable<Entry<DeckSection, CardPo
int amount = entry.getValue(); int amount = entry.getValue();
String poolCardRequest = CardDb.CardRequest.compose( String poolCardRequest = CardDb.CardRequest.compose(
card.isFoil() ? CardDb.CardRequest.compose(card.getName(), true) : card.getName(), card.isFoil() ? CardDb.CardRequest.compose(card.getName(), true) : card.getName(),
card.getEdition(), card.getArtIndex()); card.getEdition(), card.getArtIndex(), card.getColorID());
String originalRequestCandidate = null; String originalRequestCandidate = null;
for (Pair<String, Integer> originalRequest : originalCardRequests){ for (Pair<String, Integer> originalRequest : originalCardRequests){
String cardRequest = originalRequest.getLeft(); String cardRequest = originalRequest.getLeft();

View File

@@ -234,6 +234,7 @@ public interface IPaperCard extends InventoryItem, Serializable {
String getEdition(); String getEdition();
String getCollectorNumber(); String getCollectorNumber();
String getFunctionalVariant(); String getFunctionalVariant();
Set<String> getColorID();
int getArtIndex(); int getArtIndex();
boolean isFoil(); boolean isFoil();
boolean isToken(); boolean isToken();

View File

@@ -28,6 +28,8 @@ import org.apache.commons.lang3.StringUtils;
import java.io.IOException; import java.io.IOException;
import java.io.ObjectInputStream; import java.io.ObjectInputStream;
import java.util.Optional;
import java.util.Set;
/** /**
* A lightweight version of a card that matches real-world cards, to use outside of games (eg. inventory, decks, trade). * A lightweight version of a card that matches real-world cards, to use outside of games (eg. inventory, decks, trade).
@@ -55,6 +57,7 @@ public class PaperCard implements Comparable<IPaperCard>, InventoryItemFromSet,
private final boolean foil; private final boolean foil;
private Boolean hasImage; private Boolean hasImage;
private final boolean noSell; private final boolean noSell;
private Set<String> colorID;
private String sortableName; private String sortableName;
private final String functionalVariant; private final String functionalVariant;
@@ -85,6 +88,11 @@ public class PaperCard implements Comparable<IPaperCard>, InventoryItemFromSet,
return functionalVariant; return functionalVariant;
} }
@Override
public Set<String> getColorID() {
return colorID;
}
@Override @Override
public int getArtIndex() { public int getArtIndex() {
return artIndex; return artIndex;
@@ -156,7 +164,16 @@ public class PaperCard implements Comparable<IPaperCard>, InventoryItemFromSet,
this.artIndex, this.foil, String.valueOf(collectorNumber), this.artist, this.functionalVariant, false); this.artIndex, this.foil, String.valueOf(collectorNumber), this.artist, this.functionalVariant, false);
return sellable; return sellable;
} }
public PaperCard getColorIDVersion(Set<String> colors) {
if (colors == null && this.colorID == null)
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);
}
@Override @Override
public String getItemType() { public String getItemType() {
final Localizer localizer = Localizer.getInstance(); final Localizer localizer = Localizer.getInstance();
@@ -190,6 +207,12 @@ public class PaperCard implements Comparable<IPaperCard>, InventoryItemFromSet,
public PaperCard(final CardRules rules0, final String edition0, final CardRarity rarity0, public PaperCard(final CardRules rules0, final String edition0, final CardRarity rarity0,
final int artIndex0, final boolean foil0, final String collectorNumber0, final int artIndex0, final boolean foil0, final String collectorNumber0,
final String artist0, final String functionalVariant, final boolean noSell0) { 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) { if (rules0 == null || edition0 == null || rarity0 == null) {
throw new IllegalArgumentException("Cannot create card without rules, edition or rarity"); throw new IllegalArgumentException("Cannot create card without rules, edition or rarity");
} }
@@ -206,6 +229,7 @@ public class PaperCard implements Comparable<IPaperCard>, InventoryItemFromSet,
sortableName = TextUtil.toSortableName(CardTranslation.getTranslatedName(rules0.getName())); sortableName = TextUtil.toSortableName(CardTranslation.getTranslatedName(rules0.getName()));
this.functionalVariant = functionalVariant != null ? functionalVariant : IPaperCard.NO_FUNCTIONAL_VARIANT; this.functionalVariant = functionalVariant != null ? functionalVariant : IPaperCard.NO_FUNCTIONAL_VARIANT;
noSell = noSell0; noSell = noSell0;
colorID = colorID0;
} }
public static PaperCard FAKE_CARD = new PaperCard(CardRules.getUnsupportedCardNamed("Fake Card"), "Fake Edition", CardRarity.Common); public static PaperCard FAKE_CARD = new PaperCard(CardRules.getUnsupportedCardNamed("Fake Card"), "Fake Edition", CardRarity.Common);
@@ -232,6 +256,9 @@ public class PaperCard implements Comparable<IPaperCard>, InventoryItemFromSet,
} }
if (!getCollectorNumber().equals(other.getCollectorNumber())) if (!getCollectorNumber().equals(other.getCollectorNumber()))
return false; return false;
// colorID can be NULL
if (getColorID() != other.getColorID())
return false;
return (other.foil == foil) && (other.artIndex == artIndex); return (other.foil == foil) && (other.artIndex == artIndex);
} }
@@ -244,10 +271,11 @@ public class PaperCard implements Comparable<IPaperCard>, InventoryItemFromSet,
public int hashCode() { public int hashCode() {
final int code = (name.hashCode() * 11) + (edition.hashCode() * 59) + final int code = (name.hashCode() * 11) + (edition.hashCode() * 59) +
(artIndex * 2) + (getCollectorNumber().hashCode() * 383); (artIndex * 2) + (getCollectorNumber().hashCode() * 383);
final int id = Optional.ofNullable(colorID).map(Set::hashCode).orElse(0);
if (foil) { if (foil) {
return code + 1; return code + id + 1;
} }
return code; return code + id;
} }
// FIXME: Check // FIXME: Check

View File

@@ -2,6 +2,7 @@ package forge.item;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Locale; import java.util.Locale;
import java.util.Set;
import forge.card.*; import forge.card.*;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
@@ -152,6 +153,11 @@ public class PaperToken implements InventoryItemFromSet, IPaperCard {
return IPaperCard.NO_FUNCTIONAL_VARIANT; return IPaperCard.NO_FUNCTIONAL_VARIANT;
} }
@Override
public Set<String> getColorID() {
return null;
}
@Override @Override
public int getArtIndex() { public int getArtIndex() {
return artIndex; return artIndex;

View File

@@ -572,6 +572,10 @@ public class GameAction {
game.getTriggerHandler().registerActiveTrigger(copied, false); game.getTriggerHandler().registerActiveTrigger(copied, false);
} }
if (c.hasChosenColorSpire()) {
copied.setChosenColorID(ImmutableSet.copyOf(c.getChosenColorID()));
}
// update state for view // update state for view
copied.updateStateForView(); copied.updateStateForView();
@@ -2223,14 +2227,18 @@ public class GameAction {
c.setChosenNumber(chosen); c.setChosenNumber(chosen);
} }
for (Card c : spires) { for (Card c : spires) {
if (!c.hasChosenColor()) { // 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 (takesAction.isAI()) {
List<String> colorChoices = new ArrayList<>(MagicColor.Constant.ONLY_COLORS); List<String> colorChoices = new ArrayList<>(MagicColor.Constant.ONLY_COLORS);
String prompt = CardTranslation.getTranslatedName(c.getName()) + ": " + String prompt = CardTranslation.getTranslatedName(c.getName()) + ": " +
Localizer.getInstance().getMessage("lblChooseNColors", Lang.getNumeral(2)); Localizer.getInstance().getMessage("lblChooseNColors", Lang.getNumeral(2));
SpellAbility sa = new SpellAbility.EmptySa(ApiType.ChooseColor, c, takesAction); SpellAbility sa = new SpellAbility.EmptySa(ApiType.ChooseColor, c, takesAction);
sa.putParam("AILogic", "MostProminentInComputerDeck"); sa.putParam("AILogic", "MostProminentInComputerDeck");
List<String> chosenColors = takesAction.getController().chooseColors(prompt, sa, 2, 2, colorChoices); Set<String> chosenColors = new HashSet<>(takesAction.getController().chooseColors(prompt, sa, 2, 2, colorChoices));
c.setChosenColors(chosenColors); c.setChosenColorID(chosenColors);
}
} }
} }
takesAction = game.getNextPlayerAfter(takesAction); takesAction = game.getNextPlayerAfter(takesAction);

View File

@@ -199,6 +199,8 @@ public class CloneEffect extends SpellAbilityEffect {
if (sa.hasParam("RememberCloneOrigin")) { if (sa.hasParam("RememberCloneOrigin")) {
tgtCard.addRemembered(cardToCopy); tgtCard.addRemembered(cardToCopy);
} }
// spire
tgtCard.setChosenColorID(cardToCopy.getChosenColorID());
game.fireEvent(new GameEventCardStatsChanged(tgtCard)); game.fireEvent(new GameEventCardStatsChanged(tgtCard));
} }

View File

@@ -318,6 +318,8 @@ public class CopyPermanentEffect extends TokenEffectBase {
copy.setState(copy.getCurrentStateName(), true, true); copy.setState(copy.getCurrentStateName(), true, true);
} }
} }
// spire
copy.setChosenColorID(original.getChosenColorID());
copy.setTokenSpawningAbility(sa); copy.setTokenSpawningAbility(sa);
copy.setGamePieceType(GamePieceType.TOKEN); copy.setGamePieceType(GamePieceType.TOKEN);

View File

@@ -119,7 +119,7 @@ public class ManaEffect extends SpellAbilityEffect {
} }
} }
if (choiceString.toString().isEmpty() && "Combo ColorIdentity".equals(abMana.getOrigProduced())) { if (choiceString.toString().isEmpty() && ("Combo ColorIdentity".equals(abMana.getOrigProduced()) || "Combo Spire".equals(abMana.getOrigProduced()))) {
// No mana could be produced here (non-EDH match?), so cut short // No mana could be produced here (non-EDH match?), so cut short
continue; continue;
} }

View File

@@ -293,6 +293,7 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars, ITr
private String chosenType2 = ""; private String chosenType2 = "";
private List<String> notedTypes = new ArrayList<>(); private List<String> notedTypes = new ArrayList<>();
private List<String> chosenColors; private List<String> chosenColors;
private Set<String> chosenColorID;
private List<String> chosenName = new ArrayList<>(); private List<String> chosenName = new ArrayList<>();
private Integer chosenNumber; private Integer chosenNumber;
private Player chosenPlayer; private Player chosenPlayer;
@@ -399,6 +400,8 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars, ITr
view.updateSickness(this); view.updateSickness(this);
view.updateClassLevel(this); view.updateClassLevel(this);
view.updateDraftAction(this); view.updateDraftAction(this);
if (paperCard != null)
setChosenColorID(paperCard.getColorID());
} }
public boolean changeToState(final CardStateName state) { public boolean changeToState(final CardStateName state) {
@@ -2118,7 +2121,19 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars, ITr
public boolean hasChosenColor(String s) { public boolean hasChosenColor(String s) {
return chosenColors != null && chosenColors.contains(s); return chosenColors != null && chosenColors.contains(s);
} }
public final Set<String> getChosenColorID() {
if (chosenColorID == null) {
return Sets.newHashSet();
}
return chosenColorID;
}
public final void setChosenColorID(final Set<String> s) {
chosenColorID = s;
view.updateChosenColorID(this);
}
public boolean hasChosenColorSpire() {
return chosenColorID != null && !chosenColorID.isEmpty();
}
public final Card getChosenCard() { public final Card getChosenCard() {
return getChosenCards().getFirst(); return getChosenCards().getFirst();
} }

View File

@@ -433,7 +433,12 @@ public class CardView extends GameEntityView {
void updateChosenColors(Card c) { void updateChosenColors(Card c) {
set(TrackableProperty.ChosenColors, c.getChosenColors()); set(TrackableProperty.ChosenColors, c.getChosenColors());
} }
public Set<String> getChosenColorID() {
return get(TrackableProperty.ChosenColorID);
}
void updateChosenColorID(Card c) {
set(TrackableProperty.ChosenColorID, c.getChosenColorID());
}
public FCollectionView<CardView> getMergedCardsCollection() { public FCollectionView<CardView> getMergedCardsCollection() {
return get(TrackableProperty.MergedCardsCollection); return get(TrackableProperty.MergedCardsCollection);
} }

View File

@@ -654,6 +654,10 @@ public class AbilityManaPart implements java.io.Serializable {
if (origProduced.contains("Chosen")) { if (origProduced.contains("Chosen")) {
origProduced = origProduced.replace("Chosen", getChosenColor(sa)); origProduced = origProduced.replace("Chosen", getChosenColor(sa));
} }
// replace Chosen for Spire colors
if (origProduced.contains("ColorID")) {
origProduced = origProduced.replace("ColorID", getChosenColorID(sa));
}
if (origProduced.contains("NotedColors")) { if (origProduced.contains("NotedColors")) {
// Should only be used for Paliano, the High City // Should only be used for Paliano, the High City
if (sa.getActivatingPlayer() == null) { if (sa.getActivatingPlayer() == null) {
@@ -697,6 +701,21 @@ public class AbilityManaPart implements java.io.Serializable {
return sb.length() == 0 ? "" : sb.substring(0, sb.length() - 1); return sb.length() == 0 ? "" : sb.substring(0, sb.length() - 1);
} }
public String getChosenColorID(SpellAbility sa) {
if (sa == null) {
return "";
}
Card card = sa.getHostCard();
if (card != null && card.hasChosenColorSpire()) {
StringBuilder values = new StringBuilder();
for (String s : card.getChosenColorID()) {
values.append(MagicColor.toShortString(MagicColor.fromName(s))).append(" ");
}
return values.toString();
}
return "";
}
public String getChosenColor(SpellAbility sa) { public String getChosenColor(SpellAbility sa) {
if (sa == null) { if (sa == null) {
return ""; return "";

View File

@@ -67,6 +67,7 @@ public enum TrackableProperty {
ChosenType2(TrackableTypes.StringType), ChosenType2(TrackableTypes.StringType),
NotedTypes(TrackableTypes.StringListType), NotedTypes(TrackableTypes.StringListType),
ChosenColors(TrackableTypes.StringListType), ChosenColors(TrackableTypes.StringListType),
ChosenColorID(TrackableTypes.StringSetType),
ChosenCards(TrackableTypes.CardViewCollectionType), ChosenCards(TrackableTypes.CardViewCollectionType),
ChosenNumber(TrackableTypes.StringType), ChosenNumber(TrackableTypes.StringType),
StoredRolls(TrackableTypes.StringListType), StoredRolls(TrackableTypes.StringListType),

View File

@@ -20,8 +20,10 @@ package forge.screens.deckeditor.controllers;
import java.awt.Toolkit; import java.awt.Toolkit;
import java.awt.event.InputEvent; import java.awt.event.InputEvent;
import java.awt.event.KeyEvent; import java.awt.event.KeyEvent;
import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Map.Entry; import java.util.Map.Entry;
import java.util.Set;
import javax.swing.JMenu; import javax.swing.JMenu;
import javax.swing.JPopupMenu; import javax.swing.JPopupMenu;
@@ -30,6 +32,7 @@ import javax.swing.SwingUtilities;
import com.google.common.collect.Iterables; import com.google.common.collect.Iterables;
import forge.card.MagicColor;
import forge.deck.CardPool; import forge.deck.CardPool;
import forge.deck.Deck; import forge.deck.Deck;
import forge.deck.DeckBase; import forge.deck.DeckBase;
@@ -65,6 +68,7 @@ import forge.toolbox.FLabel;
import forge.toolbox.FSkin; import forge.toolbox.FSkin;
import forge.util.Aggregates; import forge.util.Aggregates;
import forge.util.ItemPool; import forge.util.ItemPool;
import forge.util.Lang;
import forge.util.Localizer; import forge.util.Localizer;
import forge.view.FView; import forge.view.FView;
@@ -576,5 +580,23 @@ public abstract class ACEditorBase<TItem extends InventoryItem, TModel extends D
InputEvent.SHIFT_DOWN_MASK | Toolkit.getDefaultToolkit().getMenuShortcutKeyMask(), InputEvent.SHIFT_DOWN_MASK | Toolkit.getDefaultToolkit().getMenuShortcutKeyMask(),
InputEvent.ALT_DOWN_MASK | Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()); InputEvent.ALT_DOWN_MASK | Toolkit.getDefaultToolkit().getMenuShortcutKeyMask());
} }
public void addSetColorID() {
String label = localizer.getMessage("lblColorIdentity");
CardManager cardManager = (CardManager) CDeckEditorUI.SINGLETON_INSTANCE.getCurrentEditorController().getDeckManager();
PaperCard existingCard = cardManager.getSelectedItem();
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));
// make an updated version
PaperCard updated = existingCard.getColorIDVersion(colors);
// remove *quantity* instances of existing card
CDeckEditorUI.SINGLETON_INSTANCE.removeSelectedCards(false, 1);
// add *quantity* into the deck and set them as selected
cardManager.addItem(updated, 1);
cardManager.setSelectedItem(updated);
}, true, true);
}
}
} }
} }

View File

@@ -375,6 +375,7 @@ public final class CEditorConstructed extends CDeckEditor<Deck> {
if (foilAvailable) { if (foilAvailable) {
cmb.addMakeFoils(); cmb.addMakeFoils();
} }
cmb.addSetColorID();
} }
/* (non-Javadoc) /* (non-Javadoc)

View File

@@ -12,6 +12,7 @@ import forge.Forge.KeyInputAdapter;
import forge.Graphics; import forge.Graphics;
import forge.assets.*; import forge.assets.*;
import forge.card.CardEdition; import forge.card.CardEdition;
import forge.card.MagicColor;
import forge.deck.io.DeckPreferences; import forge.deck.io.DeckPreferences;
import forge.gamemodes.limited.BoosterDraft; import forge.gamemodes.limited.BoosterDraft;
import forge.gamemodes.planarconquest.ConquestUtil; import forge.gamemodes.planarconquest.ConquestUtil;
@@ -1799,6 +1800,8 @@ public class FDeckEditor extends TabPageScreen<FDeckEditor> {
CardManagerPage cardSourceSection; CardManagerPage cardSourceSection;
DeckSection destination = DeckSection.matchingSection(card); DeckSection destination = DeckSection.matchingSection(card);
final DeckSectionPage destinationPage = parentScreen.getPageForSection(destination); final DeckSectionPage destinationPage = parentScreen.getPageForSection(destination);
// val for colorID setup
int val;
switch (deckSection) { switch (deckSection) {
default: default:
case Main: case Main:
@@ -1841,6 +1844,19 @@ public class FDeckEditor extends TabPageScreen<FDeckEditor> {
} }
} }
addCommanderItems(menu, card); addCommanderItems(menu, card);
if ((val = card.getRules().getSetColorID()) > 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<>() {
@Override
public void run(List<String> result) {
addCard(card.getColorIDVersion(new HashSet<>(result)));
removeCard(card);
}
});
}));
}
break; break;
case Sideboard: case Sideboard:
cardSourceSection = parentScreen.isLimitedEditor() ? parentScreen.getMainDeckPage() : parentScreen.getCatalogPage(); cardSourceSection = parentScreen.isLimitedEditor() ? parentScreen.getMainDeckPage() : parentScreen.getCatalogPage();
@@ -1880,6 +1896,19 @@ public class FDeckEditor extends TabPageScreen<FDeckEditor> {
} }
} }
addCommanderItems(menu, card); addCommanderItems(menu, card);
if ((val = card.getRules().getSetColorID()) > 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<>() {
@Override
public void run(List<String> result) {
addCard(card.getColorIDVersion(new HashSet<>(result)));
removeCard(card);
}
});
}));
}
break; break;
case Commander: case Commander:
if (parentScreen.editorType != EditorType.PlanarConquest || isPartnerCommander(card)) { if (parentScreen.editorType != EditorType.PlanarConquest || isPartnerCommander(card)) {

View File

@@ -44,6 +44,7 @@ public class ImageView<T extends InventoryItem> extends ItemView<T> {
private static final float PADDING = Utils.scale(5); private static final float PADDING = Utils.scale(5);
private static final float PILE_SPACING_Y = 0.1f; private static final float PILE_SPACING_Y = 0.1f;
private static final FSkinFont LABEL_FONT = FSkinFont.get(12); private static final FSkinFont LABEL_FONT = FSkinFont.get(12);
private TextRenderer textRenderer = new TextRenderer(true);
private static FSkinColor getGroupHeaderForeColor() { private static FSkinColor getGroupHeaderForeColor() {
if (Forge.isMobileAdventureMode) if (Forge.isMobileAdventureMode)
@@ -1029,6 +1030,7 @@ public class ImageView<T extends InventoryItem> extends ItemView<T> {
private boolean selected, deckSelectMode, showRanking; private boolean selected, deckSelectMode, showRanking;
private final float IMAGE_SIZE = CardRenderer.MANA_SYMBOL_SIZE; private final float IMAGE_SIZE = CardRenderer.MANA_SYMBOL_SIZE;
private DeckProxy deckProxy = null; private DeckProxy deckProxy = null;
private StringBuffer colorID = new StringBuffer();
private FImageComplex deckCover = null; private FImageComplex deckCover = null;
private Texture dpImg = null; private Texture dpImg = null;
//private TextureRegion tr; //private TextureRegion tr;
@@ -1055,6 +1057,20 @@ public class ImageView<T extends InventoryItem> extends ItemView<T> {
draftRankImage = FSkinImage.DRAFTRANK_C; draftRankImage = FSkinImage.DRAFTRANK_C;
} }
} }
if (((PaperCard) item).getColorID() != null) {
for (String s : ((PaperCard) item).getColorID()) {
if ("white".equalsIgnoreCase(s))
colorID.append("{W}");
if ("green".equalsIgnoreCase(s))
colorID.append("{G}");
if ("red".equalsIgnoreCase(s))
colorID.append("{R}");
if ("blue".equalsIgnoreCase(s))
colorID.append("{U}");
if ("black".equalsIgnoreCase(s))
colorID.append("{B}");
}
}
} }
} }
@@ -1136,6 +1152,10 @@ public class ImageView<T extends InventoryItem> extends ItemView<T> {
} }
} }
} }
// spire colors
if (!colorID.isEmpty()) {
textRenderer.drawText(g, colorID.toString(), FSkinFont.forHeight(w / 5), Color.WHITE, x, y + h / 4, w, h, y, h, false, Align.center, true);
}
} else if (item instanceof ConquestCommander) { } else if (item instanceof ConquestCommander) {
CardRenderer.drawCard(g, ((ConquestCommander) item).getCard(), x, y, w, h, pos); CardRenderer.drawCard(g, ((ConquestCommander) item).getCard(), x, y, w, h, pos);
} else if (deckSelectMode) { } else if (deckSelectMode) {

View File

@@ -4,5 +4,6 @@ Types:Land
Text:As you create your deck, circle two of the colors below. Text:As you create your deck, circle two of the colors below.
R:Event$ Moved | ValidCard$ Card.Self | Destination$ Battlefield | ReplacementResult$ Updated | ReplaceWith$ ETBTapped | Description$ CARDNAME enters tapped. R:Event$ Moved | ValidCard$ Card.Self | Destination$ Battlefield | ReplacementResult$ Updated | ReplaceWith$ ETBTapped | Description$ CARDNAME enters tapped.
SVar:ETBTapped:DB$ Tap | Defined$ Self | ETB$ True SVar:ETBTapped:DB$ Tap | Defined$ Self | ETB$ True
A:AB$ Mana | Cost$ T | Produced$ Combo Chosen | SpellDescription$ Add one mana of either of the circled colors. A:AB$ Mana | Cost$ T | Produced$ Combo ColorID | SpellDescription$ Add one mana of either of the circled colors.
Oracle:As you create your deck, circle two of the colors below.\nCryptic Spires enters tapped.\n{T}: Add one mana of either of the circled colors. Oracle:As you create your deck, circle two of the colors below.\nCryptic Spires enters tapped.\n{T}: Add one mana of either of the circled colors.
SETCOLORID:2

View File

@@ -487,6 +487,16 @@ public class CardDetailUtil {
area.append(")"); area.append(")");
} }
// chosen spire
if (card.getChosenColorID() != null && !card.getChosenColorID().isEmpty()) {
if (area.length() != 0) {
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(")");
}
// chosen color // chosen color
if (card.getChosenColors() != null && !card.getChosenColors().isEmpty()) { if (card.getChosenColors() != null && !card.getChosenColors().isEmpty()) {
if (area.length() != 0) { if (area.length() != 0) {

View File

@@ -57,8 +57,9 @@ public enum ColumnDef {
NAME("lblName", "lblName", 180, false, SortState.ASC, NAME("lblName", "lblName", 180, false, SortState.ASC,
from -> { from -> {
if (from.getKey() instanceof PaperCard) { if (from.getKey() instanceof PaperCard) {
String spire = ((PaperCard) from.getKey()).getColorID() == null ? "" : ((PaperCard) from.getKey()).getColorID().toString();
String sortableName = ((PaperCard)from.getKey()).getSortableName(); String sortableName = ((PaperCard)from.getKey()).getSortableName();
return sortableName == null ? TextUtil.toSortableName(from.getKey().getName()) : sortableName; return sortableName == null ? TextUtil.toSortableName(from.getKey().getName() + spire) : sortableName + spire;
} }
return TextUtil.toSortableName(from.getKey().getName()); return TextUtil.toSortableName(from.getKey().getName());
}, },