mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-16 18:58:00 +00:00
Flavor Names (#8849)
* Make getAllFaces return nonnull list * Optimize Predicates * CardDB and script syntax changes * Apply syntax changes * In-game support for flavor names * Add display names to PaperCards * Support searching by flavor names * Remove some WIP stuff * Update PaperCard translation key. * Update capitalization * Auto-map to variants when edition entry uses a flavor name * Consolidate display name logic. * Added syntax for generating flavor named variants in edition files. * Some examples of new syntax. * Ignore flavored oracle text when searching rules text * add hasFlavorName * Add image key * Get correct variant from card requests with flavor names.
This commit is contained in:
@@ -68,10 +68,6 @@ public class StaticData {
|
||||
this(cardReader, null, customCardReader, null, editionFolder, customEditionsFolder, blockDataFolder, "", cardArtPreference, enableUnknownCards, loadNonLegalCards, false, false);
|
||||
}
|
||||
|
||||
public StaticData(CardStorageReader cardReader, CardStorageReader tokenReader, CardStorageReader customCardReader, CardStorageReader customTokenReader, String editionFolder, String customEditionsFolder, String blockDataFolder, String setLookupFolder, String cardArtPreference, boolean enableUnknownCards, boolean loadNonLegalCards, boolean allowCustomCardsInDecksConformance){
|
||||
this(cardReader, tokenReader, customCardReader, customTokenReader, editionFolder, customEditionsFolder, blockDataFolder, setLookupFolder, cardArtPreference, enableUnknownCards, loadNonLegalCards, allowCustomCardsInDecksConformance, false);
|
||||
}
|
||||
|
||||
public StaticData(CardStorageReader cardReader, CardStorageReader tokenReader, CardStorageReader customCardReader, CardStorageReader customTokenReader, String editionFolder, String customEditionsFolder, String blockDataFolder, String setLookupFolder, String cardArtPreference, boolean enableUnknownCards, boolean loadNonLegalCards, boolean allowCustomCardsInDecksConformance, boolean enableSmartCardArtSelection) {
|
||||
this.cardReader = cardReader;
|
||||
this.tokenReader = tokenReader;
|
||||
@@ -81,8 +77,9 @@ public class StaticData {
|
||||
this.enableSmartCardArtSelection = enableSmartCardArtSelection;
|
||||
this.loadNonLegalCards = loadNonLegalCards;
|
||||
lastInstance = this;
|
||||
List<String> funnyCards = new ArrayList<>();
|
||||
List<String> filtered = new ArrayList<>();
|
||||
Set<String> funnyCards = new HashSet<>();
|
||||
Set<String> filtered = new HashSet<>();
|
||||
|
||||
editions.append(new CardEdition.Collection(new CardEdition.Reader(new File(customEditionsFolder), true)));
|
||||
|
||||
{
|
||||
@@ -108,7 +105,7 @@ public class StaticData {
|
||||
|
||||
final String cardName = card.getName();
|
||||
|
||||
if (!loadNonLegalCards && !card.getType().isLand() && funnyCards.contains(cardName))
|
||||
if (!loadNonLegalCards && funnyCards.contains(cardName) && !card.getType().isBasicLand())
|
||||
filtered.add(cardName);
|
||||
|
||||
if (card.isVariant()) {
|
||||
@@ -131,12 +128,11 @@ public class StaticData {
|
||||
}
|
||||
}
|
||||
|
||||
if (!filtered.isEmpty()) {
|
||||
Collections.sort(filtered);
|
||||
}
|
||||
commonCards = new CardDb(regularCards, editions, filtered);
|
||||
variantCards = new CardDb(variantsCards, editions, filtered);
|
||||
|
||||
commonCards = new CardDb(regularCards, editions, filtered, cardArtPreference);
|
||||
variantCards = new CardDb(variantsCards, editions, filtered, cardArtPreference);
|
||||
commonCards.setCardArtPreference(cardArtPreference);
|
||||
variantCards.setCardArtPreference(cardArtPreference);
|
||||
|
||||
//must initialize after establish field values for the sake of card image logic
|
||||
commonCards.initialize(false, false, enableUnknownCards);
|
||||
@@ -561,7 +557,6 @@ public class StaticData {
|
||||
* @param allowedSetCodes The list of the allowed set codes to consider when looking for alternative card art
|
||||
* candidates. If the list is not null and not empty, will be used in combination with the
|
||||
* <code>isLegal</code> predicate.
|
||||
* @see CardDb#isLegal(List<String>)
|
||||
* @return an instance of <code>PaperCard</code> that is the selected alternative candidate, or <code>null</code>
|
||||
* if None could be found.
|
||||
*/
|
||||
|
||||
@@ -17,10 +17,7 @@
|
||||
*/
|
||||
package forge.card;
|
||||
|
||||
import com.google.common.collect.ListMultimap;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Maps;
|
||||
import com.google.common.collect.Multimaps;
|
||||
import com.google.common.collect.*;
|
||||
import forge.ImageKeys;
|
||||
import forge.StaticData;
|
||||
import forge.card.CardEdition.EditionEntry;
|
||||
@@ -30,7 +27,6 @@ import forge.item.IPaperCard;
|
||||
import forge.item.PaperCard;
|
||||
import forge.util.Lang;
|
||||
import forge.util.TextUtil;
|
||||
import forge.util.lang.LangEnglish;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
|
||||
@@ -53,12 +49,15 @@ public final class CardDb implements ICardDatabase, IDeckGenPool {
|
||||
private final Map<String, ICardFace> facesByName = Maps.newTreeMap(String.CASE_INSENSITIVE_ORDER);
|
||||
private final Map<String, String> normalizedNames = Maps.newTreeMap(String.CASE_INSENSITIVE_ORDER);
|
||||
private static Map<String, String> artPrefs = Maps.newHashMap();
|
||||
/**
|
||||
* Map of flavor names to the identifier of the functional variant on which they appear in their respective card rules.
|
||||
*/
|
||||
private final Map<String, String> flavorNameMappings = Maps.newHashMap();
|
||||
|
||||
private final Map<String, String> alternateName = Maps.newTreeMap(String.CASE_INSENSITIVE_ORDER);
|
||||
private final Map<String, Integer> artIds = Maps.newHashMap();
|
||||
|
||||
private final CardEdition.Collection editions;
|
||||
private List<String> filtered;
|
||||
private final Set<String> filtered;
|
||||
|
||||
private Map<String, Boolean> nonLegendaryCreatureNames = Maps.newHashMap();
|
||||
|
||||
@@ -294,11 +293,15 @@ public final class CardDb implements ICardDatabase, IDeckGenPool {
|
||||
}
|
||||
}
|
||||
|
||||
public CardDb(Map<String, CardRules> rules, CardEdition.Collection editions0, List<String> filteredCards, String cardArtPreference) {
|
||||
public CardDb(Map<String, CardRules> rules, CardEdition.Collection editions0, Set<String> filteredCards) {
|
||||
this.filtered = filteredCards;
|
||||
this.rulesByName = rules;
|
||||
this.editions = editions0;
|
||||
|
||||
//Collects additional mappings used for flavor names
|
||||
//Need an extra map for these to avoid ConcurrentModificationException
|
||||
Map<String, CardRules> extraRuleMappings = new HashMap<>();
|
||||
|
||||
// create faces list from rules
|
||||
for (final CardRules rule : rules.values()) {
|
||||
if (filteredCards.contains(rule.getName()))
|
||||
@@ -306,8 +309,12 @@ public final class CardDb implements ICardDatabase, IDeckGenPool {
|
||||
for (ICardFace face : rule.getAllFaces()) {
|
||||
addFaceToDbNames(face);
|
||||
}
|
||||
if (rule.hasFunctionalVariants()){
|
||||
cacheFlavorNames(rule, extraRuleMappings);
|
||||
}
|
||||
setCardArtPreference(cardArtPreference);
|
||||
}
|
||||
|
||||
rulesByName.putAll(extraRuleMappings);
|
||||
}
|
||||
|
||||
private void addFaceToDbNames(ICardFace face) {
|
||||
@@ -321,14 +328,40 @@ public final class CardDb implements ICardDatabase, IDeckGenPool {
|
||||
normalizedNames.put(normalName, name);
|
||||
}
|
||||
|
||||
final String altName = face.getAltName();
|
||||
if (altName != null) {
|
||||
alternateName.put(altName, face.getName());
|
||||
if(face.hasFunctionalVariants()) {
|
||||
for(ICardFace varFace : face.getFunctionalVariants().values())
|
||||
cacheFlavorName(varFace);
|
||||
}
|
||||
if (face.getFlavorName() != null) //Probably shouldn't be putting a flavor name on the main print?
|
||||
cacheFlavorName(face);
|
||||
}
|
||||
|
||||
private void cacheFlavorName(ICardFace face) {
|
||||
String altName = face.getFlavorName();
|
||||
if(altName == null)
|
||||
return;
|
||||
facesByName.putIfAbsent(altName, face);
|
||||
final String normalAltName = StringUtils.stripAccents(altName);
|
||||
if (!normalAltName.equals(altName)) {
|
||||
normalizedNames.put(normalAltName, altName);
|
||||
}
|
||||
}
|
||||
|
||||
private void cacheFlavorNames(CardRules rules, Map<String, CardRules> map) {
|
||||
if(rules.getSupportedFunctionalVariants() == null)
|
||||
return;
|
||||
boolean hasFlavorName = false;
|
||||
String baseName = rules.getName();
|
||||
for(String variantName : rules.getSupportedFunctionalVariants()) {
|
||||
String name = rules.getDisplayNameForVariant(variantName);
|
||||
if(baseName.equals(name))
|
||||
continue;
|
||||
hasFlavorName = true;
|
||||
map.put(name, rules);
|
||||
flavorNameMappings.put(name, variantName);
|
||||
}
|
||||
if(hasFlavorName)
|
||||
flavorNameMappings.put(baseName, IPaperCard.NO_FUNCTIONAL_VARIANT);
|
||||
}
|
||||
|
||||
private void addSetCard(CardEdition e, EditionEntry cis, CardRules cr) {
|
||||
@@ -337,16 +370,40 @@ public final class CardDb implements ICardDatabase, IDeckGenPool {
|
||||
if (artIds.containsKey(key)) {
|
||||
artIdx = artIds.get(key) + 1;
|
||||
}
|
||||
|
||||
artIds.put(key, artIdx);
|
||||
addCard(new PaperCard(cr, e.getCode(), cis.rarity(), artIdx, false, cis.collectorNumber(), cis.artistName(), cis.functionalVariantName()));
|
||||
|
||||
String variantName = cis.getFunctionalVariantName();
|
||||
String flavorName = cis.getFlavorName();
|
||||
assert(variantName == null || flavorName == null); //Can't currently assign both this way.
|
||||
|
||||
if(variantName == null && !cr.getName().equals(cis.name())) {
|
||||
//If an edition entry uses a known flavor name without specifying the variant, swap to that variant.
|
||||
variantName = flavorNameMappings.get(cis.name());
|
||||
//System.out.printf("Auto-mapping flavor name \"%s\" -> \"%s\" $%s\n", cis.name(), cr.getName(), variantName);
|
||||
}
|
||||
if(flavorName != null) {
|
||||
String suggestedFlavorName = e.getCode().startsWith("OM") ? "Alchemy"
|
||||
: e.getCode().equals("SLX") ? "UniversesWithin"
|
||||
: null;
|
||||
variantName = cr.findOrCreateVariantForFlavorName(flavorName, suggestedFlavorName);
|
||||
String normalizedFlavorName = cr.getDisplayNameForVariant(variantName);
|
||||
if(!flavorNameMappings.containsKey(normalizedFlavorName)) {
|
||||
flavorNameMappings.put(normalizedFlavorName, variantName);
|
||||
rulesByName.put(normalizedFlavorName, cr);
|
||||
cacheFlavorName(cr.getMainPart().getFunctionalVariant(variantName));
|
||||
if(cr.getOtherPart() != null)
|
||||
cacheFlavorName(cr.getOtherPart().getFunctionalVariant(variantName));
|
||||
}
|
||||
}
|
||||
|
||||
addCard(new PaperCard(cr, e.getCode(), cis.rarity(), artIdx, false, cis.collectorNumber(), cis.artistName(), variantName));
|
||||
}
|
||||
|
||||
private boolean addFromSetByName(String cardName, CardEdition ed, CardRules cr) {
|
||||
List<EditionEntry> cardsInSet = ed.getCardInSet(cardName); // empty collection if not present
|
||||
if (cr.hasFunctionalVariants()) {
|
||||
cardsInSet = cardsInSet.stream().filter(c -> StringUtils.isEmpty(c.functionalVariantName())
|
||||
|| cr.getSupportedFunctionalVariants().contains(c.functionalVariantName())
|
||||
cardsInSet = cardsInSet.stream().filter(c -> StringUtils.isEmpty(c.getFunctionalVariantName())
|
||||
|| cr.getSupportedFunctionalVariants().contains(c.getFunctionalVariantName())
|
||||
).collect(Collectors.toList());
|
||||
}
|
||||
if (cardsInSet.isEmpty())
|
||||
@@ -383,9 +440,6 @@ public final class CardDb implements ICardDatabase, IDeckGenPool {
|
||||
CardEdition upcomingSet = null;
|
||||
Date today = new Date();
|
||||
|
||||
// do this first so they're not considered missing
|
||||
buildRenamedCards();
|
||||
|
||||
for (CardEdition e : editions.getOrderedEditions()) {
|
||||
boolean coreOrExpSet = e.getType() == CardEdition.Type.CORE || e.getType() == CardEdition.Type.EXPANSION;
|
||||
boolean isCoreExpSet = coreOrExpSet || e.getType() == CardEdition.Type.REPRINT;
|
||||
@@ -403,8 +457,8 @@ public final class CardDb implements ICardDatabase, IDeckGenPool {
|
||||
continue;
|
||||
}
|
||||
if (cr.hasFunctionalVariants()) {
|
||||
if (StringUtils.isNotEmpty(cis.functionalVariantName())
|
||||
&& !cr.getSupportedFunctionalVariants().contains(cis.functionalVariantName())) {
|
||||
if (StringUtils.isNotEmpty(cis.getFunctionalVariantName())
|
||||
&& !cr.getSupportedFunctionalVariants().contains(cis.getFunctionalVariantName())) {
|
||||
//Supported card, unsupported variant.
|
||||
//Could note the card as missing but since these are often un-cards,
|
||||
//it's likely absent because it does something out of scope.
|
||||
@@ -455,71 +509,28 @@ public final class CardDb implements ICardDatabase, IDeckGenPool {
|
||||
reIndex();
|
||||
}
|
||||
|
||||
private void buildRenamedCards() {
|
||||
Lang lang = Lang.getInstance();
|
||||
if (lang == null) {
|
||||
// for some tests
|
||||
lang = new LangEnglish();
|
||||
}
|
||||
// for now just check Universes Within
|
||||
for (EditionEntry cis : editions.get("SLX").getCards()) {
|
||||
String orgName = alternateName.get(cis.name());
|
||||
if (orgName != null) {
|
||||
// found original (beyond) print
|
||||
CardRules org = getRules(orgName);
|
||||
|
||||
CardFace renamedMain = (CardFace) ((CardFace) org.getMainPart()).clone();
|
||||
renamedMain.setName(renamedMain.getAltName());
|
||||
renamedMain.setAltName(null);
|
||||
// TODO this could mess up some "named ..." cardname literals but there's no printing like that currently
|
||||
renamedMain.setOracleText(renamedMain.getOracleText()
|
||||
.replace(orgName, renamedMain.getName())
|
||||
.replace(lang.getNickName(orgName), lang.getNickName(renamedMain.getName()))
|
||||
);
|
||||
facesByName.put(renamedMain.getName(), renamedMain);
|
||||
CardFace renamedOther = null;
|
||||
if (org.getOtherPart() != null) {
|
||||
renamedOther = (CardFace) ((CardFace) org.getOtherPart()).clone();
|
||||
orgName = renamedOther.getName();
|
||||
renamedOther.setName(renamedOther.getAltName());
|
||||
renamedOther.setAltName(null);
|
||||
renamedOther.setOracleText(renamedOther.getOracleText()
|
||||
.replace(orgName, renamedOther.getName())
|
||||
.replace(lang.getNickName(orgName), lang.getNickName(renamedOther.getName()))
|
||||
);
|
||||
facesByName.put(renamedOther.getName(), renamedOther);
|
||||
}
|
||||
|
||||
CardRules within = new CardRules(new ICardFace[] { renamedMain, renamedOther, null, null, null, null, null }, org.getSplitType(), org.getAiHints());
|
||||
// so workshop can edit same script
|
||||
within.setNormalizedName(org.getNormalizedName());
|
||||
rulesByName.put(cis.name(), within);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void addCard(PaperCard paperCard) {
|
||||
if (filtered.contains(paperCard.getName())) {
|
||||
return;
|
||||
}
|
||||
|
||||
allCardsByName.put(paperCard.getName(), paperCard);
|
||||
String mainName = paperCard.getName();
|
||||
allCardsByName.put(mainName, paperCard);
|
||||
|
||||
if (paperCard.getRules().getSplitType() == CardSplitType.None) {
|
||||
CardRules rules = paperCard.getRules();
|
||||
if (rules.getSplitType() == CardSplitType.None && !rules.hasFunctionalVariants()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (paperCard.getRules().getOtherPart() != null) {
|
||||
//allow looking up card by the name of other faces
|
||||
allCardsByName.put(paperCard.getRules().getOtherPart().getName(), paperCard);
|
||||
}
|
||||
if (paperCard.getRules().getSplitType() == CardSplitType.Split) {
|
||||
//also include main part for split cards
|
||||
allCardsByName.put(paperCard.getRules().getMainPart().getName(), paperCard);
|
||||
} else if (paperCard.getRules().getSplitType() == CardSplitType.Specialize) {
|
||||
//also include specialize faces
|
||||
for (ICardFace face : paperCard.getRules().getSpecializeParts().values()) allCardsByName.put(face.getName(), paperCard);
|
||||
}
|
||||
//Card may have multiple names. Add it under all of them.
|
||||
|
||||
List<ICardFace> allFaces = paperCard.getAllFaces();
|
||||
Set<String> namesToAdd = new HashSet<>();
|
||||
allFaces.stream().map(ICardCharacteristics::getName).forEach(namesToAdd::add);
|
||||
allFaces.stream().map(ICardFace::getFlavorName).filter(Objects::nonNull).forEach(namesToAdd::add);
|
||||
namesToAdd.remove(mainName);
|
||||
for(String name : namesToAdd)
|
||||
allCardsByName.put(name, paperCard);
|
||||
}
|
||||
|
||||
private void reIndex() {
|
||||
@@ -560,11 +571,7 @@ public final class CardDb implements ICardDatabase, IDeckGenPool {
|
||||
|
||||
public CardRules getRules(String cardName) {
|
||||
CardRules result = rulesByName.get(cardName);
|
||||
if (result != null) {
|
||||
return result;
|
||||
} else {
|
||||
return CardRules.getUnsupportedCardNamed(cardName);
|
||||
}
|
||||
return Objects.requireNonNullElseGet(result, () -> CardRules.getUnsupportedCardNamed(cardName));
|
||||
}
|
||||
|
||||
public CardArtPreference getCardArtPreference(){ return this.defaultCardArtPreference; }
|
||||
@@ -869,10 +876,17 @@ public final class CardDb implements ICardDatabase, IDeckGenPool {
|
||||
cardQueryFilter = card -> card.getArtIndex() == cr.artIndex;
|
||||
cardQueryFilter = cardQueryFilter.and(filter);
|
||||
cards = getAllCards(cr.cardName, cardQueryFilter);
|
||||
// Note: No need to check whether "cards" is empty; the next for loop will validate condition at L699
|
||||
if (cards.isEmpty())
|
||||
return null;
|
||||
if (cards.size() == 1) // if only one candidate, there much else we should do
|
||||
return cr.isFoil ? cards.get(0).getFoiled() : cards.get(0);
|
||||
|
||||
if (flavorNameMappings.containsKey(cr.cardName)) {
|
||||
Collection<PaperCard> matchingNames = cards.stream().filter(c -> c.getDisplayName().equals(cr.cardName)).collect(Collectors.toSet());
|
||||
if(!matchingNames.isEmpty())
|
||||
cards.retainAll(matchingNames);
|
||||
}
|
||||
|
||||
/* 2. Retrieve cards based of [Frame]Set Preference
|
||||
================================================ */
|
||||
// Collect the list of all editions found for target card
|
||||
@@ -967,11 +981,11 @@ public final class CardDb implements ICardDatabase, IDeckGenPool {
|
||||
}
|
||||
|
||||
public List<PaperCard> getUniqueCardsNoAlt(String cardName) {
|
||||
return Lists.newArrayList(Maps.filterEntries(uniqueCardsByName, entry -> entry.getKey().equals(entry.getValue().getName())).get(getName(cardName)));
|
||||
return Lists.newArrayList(Maps.filterEntries(uniqueCardsByName, entry -> entry.getKey().equals(entry.getValue().getName())).get(getNormalizedName(cardName)));
|
||||
}
|
||||
|
||||
public PaperCard getUniqueByName(final String name) {
|
||||
return uniqueCardsByName.get(getName(name));
|
||||
return uniqueCardsByName.get(getNormalizedName(name));
|
||||
}
|
||||
|
||||
public Collection<ICardFace> getAllFaces() {
|
||||
@@ -979,7 +993,7 @@ public final class CardDb implements ICardDatabase, IDeckGenPool {
|
||||
}
|
||||
|
||||
public ICardFace getFaceByName(final String name) {
|
||||
return facesByName.get(getName(name));
|
||||
return facesByName.get(getNormalizedName(name));
|
||||
}
|
||||
|
||||
public boolean isNonLegendaryCreatureName(final String name) {
|
||||
@@ -1050,26 +1064,20 @@ public final class CardDb implements ICardDatabase, IDeckGenPool {
|
||||
return streamAllCardsNoAlt().filter(EDITION_NON_REPRINT).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public String getName(final String cardName) {
|
||||
return getName(cardName, false);
|
||||
}
|
||||
public String getName(String cardName, boolean engine) {
|
||||
public String getNormalizedName(final String cardName) {
|
||||
String cardName1 = cardName;
|
||||
// normalize Names first
|
||||
cardName = normalizedNames.getOrDefault(cardName, cardName);
|
||||
if (alternateName.containsKey(cardName) && engine) {
|
||||
// TODO might want to implement GUI option so it always fetches the Within version
|
||||
return alternateName.get(cardName);
|
||||
}
|
||||
return cardName;
|
||||
cardName1 = normalizedNames.getOrDefault(cardName1, cardName1);
|
||||
return cardName1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<PaperCard> getAllCards(String cardName) {
|
||||
return allCardsByName.get(getName(cardName));
|
||||
return allCardsByName.get(getNormalizedName(cardName));
|
||||
}
|
||||
|
||||
public List<PaperCard> getAllCardsNoAlt(String cardName) {
|
||||
return Lists.newArrayList(Multimaps.filterEntries(allCardsByName, entry -> entry.getKey().equals(entry.getValue().getName())).get(getName(cardName)));
|
||||
return Lists.newArrayList(Multimaps.filterEntries(allCardsByName, entry -> entry.getKey().equals(entry.getValue().getName())).get(getNormalizedName(cardName)));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1111,7 +1119,7 @@ public final class CardDb implements ICardDatabase, IDeckGenPool {
|
||||
|
||||
@Override
|
||||
public boolean contains(String name) {
|
||||
return allCardsByName.containsKey(getName(name));
|
||||
return allCardsByName.containsKey(getNormalizedName(name));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -1221,7 +1229,7 @@ public final class CardDb implements ICardDatabase, IDeckGenPool {
|
||||
int artIdx = IPaperCard.DEFAULT_ART_INDEX;
|
||||
for (EditionEntry cis : e.getCardInSet(cardName))
|
||||
paperCards.add(new PaperCard(rules, e.getCode(), cis.rarity(), artIdx++, false,
|
||||
cis.collectorNumber(), cis.artistName(), cis.functionalVariantName()));
|
||||
cis.collectorNumber(), cis.artistName(), cis.getFunctionalVariantName()));
|
||||
}
|
||||
} else {
|
||||
String lastEdition = null;
|
||||
@@ -1241,7 +1249,7 @@ public final class CardDb implements ICardDatabase, IDeckGenPool {
|
||||
int cardInSetIndex = Math.max(artIdx-1, 0); // make sure doesn't go below zero
|
||||
EditionEntry cds = cardsInSet.get(cardInSetIndex); // use ArtIndex to get the right Coll. Number
|
||||
paperCards.add(new PaperCard(rules, lastEdition, tuple.getValue(), artIdx++, false,
|
||||
cds.collectorNumber(), cds.artistName(), cds.functionalVariantName()));
|
||||
cds.collectorNumber(), cds.artistName(), cds.getFunctionalVariantName()));
|
||||
}
|
||||
}
|
||||
if (paperCards.isEmpty()) {
|
||||
|
||||
@@ -82,23 +82,17 @@ public final class CardEdition implements Comparable<CardEdition> {
|
||||
public static final EnumSet<Type> REPRINT_SET_TYPES = EnumSet.of(REPRINT, PROMO, COLLECTOR_EDITION);
|
||||
|
||||
public String getBoosterBoxDefault() {
|
||||
switch (this) {
|
||||
case CORE:
|
||||
case EXPANSION:
|
||||
return "36";
|
||||
default:
|
||||
return "0";
|
||||
}
|
||||
return switch (this) {
|
||||
case CORE, EXPANSION -> "36";
|
||||
default -> "0";
|
||||
};
|
||||
}
|
||||
|
||||
public String getFatPackDefault() {
|
||||
switch (this) {
|
||||
case CORE:
|
||||
case EXPANSION:
|
||||
return "10";
|
||||
default:
|
||||
return "0";
|
||||
}
|
||||
return switch (this) {
|
||||
case CORE, EXPANSION -> "10";
|
||||
default -> "0";
|
||||
};
|
||||
}
|
||||
|
||||
public String toString(){
|
||||
@@ -215,7 +209,7 @@ public final class CardEdition implements Comparable<CardEdition> {
|
||||
return sortableCollNr;
|
||||
}
|
||||
|
||||
public record EditionEntry(String name, String collectorNumber, CardRarity rarity, String artistName, String functionalVariantName) implements Comparable<EditionEntry> {
|
||||
public record EditionEntry(String name, String collectorNumber, CardRarity rarity, String artistName, Map<String, String> extraParams) implements Comparable<EditionEntry> {
|
||||
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
@@ -232,9 +226,9 @@ public final class CardEdition implements Comparable<CardEdition> {
|
||||
sb.append(" @");
|
||||
sb.append(artistName);
|
||||
}
|
||||
if (functionalVariantName != null) {
|
||||
if (extraParams != null) {
|
||||
sb.append(" $");
|
||||
sb.append(functionalVariantName);
|
||||
sb.append(extraParams.entrySet().stream().map(e -> String.format("\"%s\"=\"%s\"", e.getKey(), e.getValue())).collect(Collectors.joining(", ")));
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
@@ -253,6 +247,24 @@ public final class CardEdition implements Comparable<CardEdition> {
|
||||
}
|
||||
return rarity.compareTo(o.rarity);
|
||||
}
|
||||
|
||||
public String getFlavorName() {
|
||||
if(extraParams == null)
|
||||
return null;
|
||||
return extraParams.get("flavorname");
|
||||
}
|
||||
|
||||
public String getFunctionalVariantName() {
|
||||
if(extraParams == null)
|
||||
return null;
|
||||
return extraParams.get("variant");
|
||||
}
|
||||
|
||||
public String getScriptOverride() {
|
||||
if(extraParams == null)
|
||||
return null;
|
||||
return extraParams.get("script");
|
||||
}
|
||||
}
|
||||
|
||||
private final static SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd");
|
||||
@@ -589,6 +601,31 @@ public final class CardEdition implements Comparable<CardEdition> {
|
||||
}
|
||||
|
||||
public static class Reader extends StorageReaderFolder<CardEdition> {
|
||||
|
||||
public static final Pattern CARD_PATTERN = Pattern.compile(
|
||||
/*
|
||||
The following pattern will match the WAR Japanese art entries,
|
||||
it should also match the Un-set and older alternate art cards
|
||||
like Merseine from FEM.
|
||||
*/
|
||||
// Collector numbers now should allow hyphens for Planeswalker Championship Promos
|
||||
"(?:^(?<cnum>.?[0-9A-Z-]+\\S*[A-Z]*)\\s)?(?:(?<rarity>[SCURML])\\s)?(?<name>[^@$]*)(?: @(?<artist>[^$]*))?(?: \\$\\{(?<params>.+)})?$"
|
||||
);
|
||||
|
||||
public static final Pattern TOKEN_PATTERN = Pattern.compile(
|
||||
/*
|
||||
* cnum - grouping #2
|
||||
* name - grouping #3
|
||||
* artist name - grouping #5
|
||||
*/
|
||||
"(?:^(?<cnum>.?[0-9A-Z-]+\\S?[A-Z☇]*)\\s)?(?<name>[^@]*)(?: @(?<artist>.*))?$"
|
||||
);
|
||||
|
||||
public static final Pattern EXTRA_PARAMS_PATTERN = Pattern.compile(
|
||||
//Simple JSON string map parser - "key": "value". No support for escaping quotation marks or anything fancy.
|
||||
"\"([^\"]+)\"\\s*:\\s*\"([^\"]+)\",?"
|
||||
);
|
||||
|
||||
private final boolean isCustomEditions;
|
||||
|
||||
public Reader(File path) {
|
||||
@@ -610,38 +647,6 @@ public final class CardEdition implements Comparable<CardEdition> {
|
||||
protected CardEdition read(File file) {
|
||||
final Map<String, List<String>> contents = FileSection.parseSections(FileUtil.readFile(file));
|
||||
|
||||
final Pattern pattern = Pattern.compile(
|
||||
/*
|
||||
The following pattern will match the WAR Japanese art entries,
|
||||
it should also match the Un-set and older alternate art cards
|
||||
like Merseine from FEM.
|
||||
*/
|
||||
// Collector numbers now should allow hyphens for Planeswalker Championship Promos
|
||||
//"(^(?<cnum>[0-9]+.?) )?((?<rarity>[SCURML]) )?(?<name>.*)$"
|
||||
/* Ideally we'd use the named group above, but Android 6 and
|
||||
earlier don't appear to support named groups.
|
||||
So, untill support for those devices is officially dropped,
|
||||
we'll have to suffice with numbered groups.
|
||||
We are looking for:
|
||||
* cnum - grouping #2
|
||||
* rarity - grouping #4
|
||||
* name - grouping #5
|
||||
* artist name - grouping #7
|
||||
* functional variant name - grouping #9
|
||||
*/
|
||||
// "(^(.?[0-9A-Z]+.?))?(([SCURML]) )?(.*)$"
|
||||
"(^(.?[0-9A-Z-]+\\S*[A-Z]*)\\s)?(([SCURML])\\s)?([^@\\$]*)( @([^\\$]*))?( \\$(.+))?$"
|
||||
);
|
||||
|
||||
final Pattern tokenPattern = Pattern.compile(
|
||||
/*
|
||||
* cnum - grouping #2
|
||||
* name - grouping #3
|
||||
* artist name - grouping #5
|
||||
*/
|
||||
"(^(.?[0-9A-Z-]+\\S?[A-Z☇]*)\\s)?([^@]*)( @(.*))?$"
|
||||
);
|
||||
|
||||
ListMultimap<String, EditionEntry> cardMap = ArrayListMultimap.create();
|
||||
List<BoosterSlot> boosterSlots = null;
|
||||
Map<String, List<String>> customPrintSheetsToParse = new HashMap<>();
|
||||
@@ -668,18 +673,35 @@ public final class CardEdition implements Comparable<CardEdition> {
|
||||
// parse sections of the format "<collector number> <rarity> <name>"
|
||||
if (editionSectionsWithCollectorNumbers.contains(sectionName)) {
|
||||
for(String line : contents.get(sectionName)) {
|
||||
Matcher matcher = pattern.matcher(line);
|
||||
Matcher matcher = CARD_PATTERN.matcher(line);
|
||||
|
||||
if (!matcher.matches()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
String collectorNumber = matcher.group(2);
|
||||
CardRarity r = CardRarity.smartValueOf(matcher.group(4));
|
||||
String cardName = matcher.group(5);
|
||||
String artistName = matcher.group(7);
|
||||
String functionalVariantName = matcher.group(9);
|
||||
EditionEntry cis = new EditionEntry(cardName, collectorNumber, r, artistName, functionalVariantName);
|
||||
String collectorNumber = matcher.group("cnum");
|
||||
CardRarity r = CardRarity.smartValueOf(matcher.group("rarity"));
|
||||
String cardName = matcher.group("name");
|
||||
String artistName = matcher.group("artist");
|
||||
String extraParamText = matcher.group("params");
|
||||
Map<String, String> extraParams = null;
|
||||
if(!StringUtils.isBlank(extraParamText)) {
|
||||
Matcher paramMatcher = EXTRA_PARAMS_PATTERN.matcher(extraParamText);
|
||||
if(!paramMatcher.lookingAt())
|
||||
System.err.println("Ignoring malformed parameter text: " + extraParamText);
|
||||
else {
|
||||
extraParams = new HashMap<>(2);
|
||||
do {
|
||||
String k = paramMatcher.group(1).trim().toLowerCase();
|
||||
String v = paramMatcher.group(2).trim();
|
||||
if(k.isEmpty() || v.isEmpty())
|
||||
continue;
|
||||
extraParams.put(k, v);
|
||||
} while(paramMatcher.find());
|
||||
}
|
||||
}
|
||||
|
||||
EditionEntry cis = new EditionEntry(cardName, collectorNumber, r, artistName, extraParams);
|
||||
|
||||
cardMap.put(sectionName, cis);
|
||||
}
|
||||
@@ -701,15 +723,15 @@ public final class CardEdition implements Comparable<CardEdition> {
|
||||
for (String line : contents.get("tokens")) {
|
||||
if (StringUtils.isBlank(line))
|
||||
continue;
|
||||
Matcher matcher = tokenPattern.matcher(line);
|
||||
Matcher matcher = TOKEN_PATTERN.matcher(line);
|
||||
|
||||
if (!matcher.matches()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
String collectorNumber = matcher.group(2);
|
||||
String cardName = matcher.group(3);
|
||||
String artistName = matcher.group(5);
|
||||
String collectorNumber = matcher.group("cnum");
|
||||
String cardName = matcher.group("name");
|
||||
String artistName = matcher.group("artist");
|
||||
// rarity isn't used for this anyway
|
||||
EditionEntry tis = new EditionEntry(cardName, collectorNumber, CardRarity.Token, artistName, null);
|
||||
tokenMap.put(cardName, tis);
|
||||
@@ -719,14 +741,14 @@ public final class CardEdition implements Comparable<CardEdition> {
|
||||
for (String line : contents.get("other")) {
|
||||
if (StringUtils.isBlank(line))
|
||||
continue;
|
||||
Matcher matcher = tokenPattern.matcher(line);
|
||||
Matcher matcher = TOKEN_PATTERN.matcher(line);
|
||||
|
||||
if (!matcher.matches()) {
|
||||
continue;
|
||||
}
|
||||
String collectorNumber = matcher.group(2);
|
||||
String cardName = matcher.group(3);
|
||||
String artistName = matcher.group(5);
|
||||
String collectorNumber = matcher.group("cnum");
|
||||
String cardName = matcher.group("name");
|
||||
String artistName = matcher.group("artist");
|
||||
EditionEntry tis = new EditionEntry(cardName, collectorNumber, CardRarity.Unknown, artistName, null);
|
||||
otherMap.put(cardName, tis);
|
||||
}
|
||||
@@ -931,7 +953,7 @@ public final class CardEdition implements Comparable<CardEdition> {
|
||||
public final Comparator<PaperCard> CARD_EDITION_COMPARATOR = Comparator.comparing(c -> Collection.this.get(c.getEdition()));
|
||||
|
||||
public IItemReader<SealedTemplate> getBoosterGenerator() {
|
||||
return new StorageReaderBase<SealedTemplate>(null) {
|
||||
return new StorageReaderBase<>(null) {
|
||||
@Override
|
||||
public Map<String, SealedTemplate> readAll() {
|
||||
Map<String, SealedTemplate> map = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
|
||||
|
||||
@@ -17,20 +17,12 @@ import java.util.stream.Collectors;
|
||||
* <i>Do not use reference to class except for card parsing.<br>Always use reference to interface type outside of package.</i>
|
||||
*/
|
||||
final class CardFace implements ICardFace, Cloneable {
|
||||
|
||||
public enum FaceSelectionMethod { //
|
||||
USE_ACTIVE_FACE,
|
||||
USE_PRIMARY_FACE,
|
||||
COMBINE
|
||||
}
|
||||
|
||||
|
||||
private final static List<String> emptyList = Collections.unmodifiableList(new ArrayList<>());
|
||||
private final static Map<String, String> emptyMap = Collections.unmodifiableMap(new TreeMap<>());
|
||||
private final static Set<Integer> emptySet = Collections.unmodifiableSet(new HashSet<>());
|
||||
|
||||
private String name;
|
||||
private String altName = null;
|
||||
private String flavorName = null;
|
||||
private CardType type = null;
|
||||
private ManaCost manaCost = null;
|
||||
private ColorSet color = null;
|
||||
@@ -85,7 +77,7 @@ final class CardFace implements ICardFace, Cloneable {
|
||||
return variables.entrySet();
|
||||
}
|
||||
|
||||
@Override public String getAltName() { return this.altName; }
|
||||
@Override public String getFlavorName() { return this.flavorName; }
|
||||
|
||||
public CardFace(String name0) {
|
||||
this.name = name0;
|
||||
@@ -94,7 +86,7 @@ final class CardFace implements ICardFace, Cloneable {
|
||||
}
|
||||
// Here come setters to allow parser supply values
|
||||
void setName(String name) { this.name = name; }
|
||||
void setAltName(String name) { this.altName = name; }
|
||||
void setFlavorName(String name) { this.flavorName = name; }
|
||||
void setType(CardType type0) { this.type = type0; }
|
||||
void setManaCost(ManaCost manaCost0) { this.manaCost = manaCost0; }
|
||||
void setColor(ColorSet color0) { this.color = color0; }
|
||||
@@ -187,6 +179,12 @@ final class CardFace implements ICardFace, Cloneable {
|
||||
if(this.functionalVariants != null) {
|
||||
//Copy fields to undefined ones in functional variants
|
||||
for (CardFace variant : this.functionalVariants.values()) {
|
||||
assignMissingFieldsToVariant(variant);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void assignMissingFieldsToVariant(CardFace variant) {
|
||||
if(variant.oracleText == null) variant.oracleText = this.oracleText;
|
||||
if(variant.manaCost == null) variant.manaCost = this.manaCost;
|
||||
if(variant.color == null) variant.color = ColorSet.fromManaCost(variant.manaCost);
|
||||
@@ -205,7 +203,6 @@ final class CardFace implements ICardFace, Cloneable {
|
||||
if("".equals(variant.initialLoyalty)) variant.initialLoyalty = this.initialLoyalty;
|
||||
if("".equals(variant.defense)) variant.defense = this.defense;
|
||||
|
||||
//variant.assignMissingFields();
|
||||
if(variant.keywords == null) variant.keywords = this.keywords;
|
||||
else variant.keywords.addAll(0, this.keywords);
|
||||
|
||||
@@ -227,9 +224,7 @@ final class CardFace implements ICardFace, Cloneable {
|
||||
if(variant.nonAbilityText == null) variant.nonAbilityText = this.nonAbilityText;
|
||||
if(variant.draftActions == null) variant.draftActions = this.draftActions;
|
||||
if(variant.attractionLights == null) variant.attractionLights = this.attractionLights;
|
||||
if(variant.altName == null) variant.altName = this.altName;
|
||||
}
|
||||
}
|
||||
//if(variant.flavorName == null) variant.flavorName = this.flavorName; //Probably shouldn't be setting this on the main variant to begin with?
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -27,6 +27,7 @@ import forge.util.TextUtil;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static forge.card.MagicColor.Constant.BASIC_LANDS;
|
||||
import static org.apache.commons.lang3.StringUtils.containsIgnoreCase;
|
||||
@@ -43,8 +44,9 @@ public final class CardRules implements ICardCharacteristics {
|
||||
private CardSplitType splitType;
|
||||
private ICardFace mainPart;
|
||||
private ICardFace otherPart;
|
||||
|
||||
private Map<CardStateName, ICardFace> specializedParts = Maps.newHashMap();
|
||||
private List<ICardFace> allFaces;
|
||||
|
||||
private CardAiHints aiHints;
|
||||
private ColorSet colorIdentity;
|
||||
private ColorSet deckbuildingColors;
|
||||
@@ -69,6 +71,8 @@ public final class CardRules implements ICardCharacteristics {
|
||||
specializedParts.put(CardStateName.SpecializeG, faces[6]);
|
||||
}
|
||||
|
||||
allFaces = Arrays.stream(faces).filter(Objects::nonNull).collect(Collectors.toUnmodifiableList());
|
||||
|
||||
aiHints = cah;
|
||||
meldWith = "";
|
||||
partnerWith = "";
|
||||
@@ -93,6 +97,7 @@ public final class CardRules implements ICardCharacteristics {
|
||||
mainPart = newRules.mainPart;
|
||||
otherPart = newRules.otherPart;
|
||||
specializedParts = Maps.newHashMap(newRules.specializedParts);
|
||||
allFaces = newRules.allFaces;
|
||||
aiHints = newRules.aiHints;
|
||||
colorIdentity = newRules.colorIdentity;
|
||||
meldWith = newRules.meldWith;
|
||||
@@ -163,8 +168,8 @@ public final class CardRules implements ICardCharacteristics {
|
||||
return specializedParts;
|
||||
}
|
||||
|
||||
public Iterable<ICardFace> getAllFaces() {
|
||||
return Iterables.concat(Arrays.asList(mainPart, otherPart), specializedParts.values());
|
||||
public List<ICardFace> getAllFaces() {
|
||||
return allFaces;
|
||||
}
|
||||
|
||||
public boolean isTransformable() {
|
||||
@@ -464,6 +469,58 @@ public final class CardRules implements ICardCharacteristics {
|
||||
return this.supportedFunctionalVariants;
|
||||
}
|
||||
|
||||
public String getDisplayNameForVariant(String variantName) {
|
||||
if(supportedFunctionalVariants == null || !supportedFunctionalVariants.contains(variantName))
|
||||
return getName();
|
||||
|
||||
ICardFace mainFace = Objects.requireNonNullElse(mainPart.getFunctionalVariant(variantName), mainPart);
|
||||
String mainPartName = Objects.requireNonNullElse(mainFace.getFlavorName(), mainFace.getName());
|
||||
|
||||
if(splitType.getAggregationMethod() == CardSplitType.FaceSelectionMethod.COMBINE) {
|
||||
ICardFace otherFace = Objects.requireNonNullElse(otherPart.getFunctionalVariant(variantName), otherPart);
|
||||
String otherPartName = Objects.requireNonNullElse(otherFace.getFlavorName(), otherFace.getName());
|
||||
return mainPartName + " // " + otherPartName;
|
||||
}
|
||||
else
|
||||
return mainPartName;
|
||||
}
|
||||
|
||||
/* package */ String findOrCreateVariantForFlavorName(String flavorName, String suggestedVariantName) {
|
||||
Objects.requireNonNull(flavorName);
|
||||
String[] nameParts = flavorName.trim().split("\\s*//\\s*");
|
||||
flavorName = String.join(" // ", nameParts); //Normalize this just in case.
|
||||
if(otherPart != null && nameParts.length < 2)
|
||||
throw new IllegalArgumentException("Tried to assign a single flavor name to a multi-faced card. Use ' // ' as a separator in the flavorName parameter.");
|
||||
if(supportedFunctionalVariants == null)
|
||||
supportedFunctionalVariants = new HashSet<>();
|
||||
for(String variantName : this.supportedFunctionalVariants) {
|
||||
if(getDisplayNameForVariant(variantName).equals(flavorName))
|
||||
return variantName;
|
||||
}
|
||||
String variantName = suggestedVariantName != null ? suggestedVariantName : "FlavorName" + flavorName.hashCode();
|
||||
if(supportedFunctionalVariants.contains(variantName))
|
||||
variantName = variantName + flavorName.hashCode();
|
||||
|
||||
CardFace variantMain = ((CardFace) mainPart).getOrCreateFunctionalVariant(variantName);
|
||||
variantMain.setFlavorName(nameParts[0]);
|
||||
//Rudimentary name replacement. Can't do nicknames, pronouns, ability words, or flavored keywords. Need to define variants manually for that.
|
||||
if(mainPart.getOracleText().contains(mainPart.getName()))
|
||||
variantMain.setOracleText(mainPart.getOracleText().replace(mainPart.getName(), nameParts[0]));
|
||||
((CardFace) mainPart).assignMissingFieldsToVariant(variantMain);
|
||||
|
||||
if(otherPart != null) {
|
||||
CardFace variantOther = ((CardFace) otherPart).getOrCreateFunctionalVariant(variantName);
|
||||
variantOther.setFlavorName(nameParts[1]);
|
||||
if(otherPart.getOracleText().contains(otherPart.getName()))
|
||||
variantMain.setOracleText(otherPart.getOracleText().replace(otherPart.getName(), nameParts[1]));
|
||||
((CardFace) otherPart).assignMissingFieldsToVariant(variantOther);
|
||||
}
|
||||
|
||||
supportedFunctionalVariants.add(variantName);
|
||||
|
||||
return variantName;
|
||||
}
|
||||
|
||||
public ColorSet getColorIdentity() {
|
||||
return colorIdentity;
|
||||
}
|
||||
@@ -622,8 +679,6 @@ public final class CardRules implements ICardCharacteristics {
|
||||
this.altMode = CardSplitType.smartValueOf(value);
|
||||
} else if ("ALTERNATE".equals(key)) {
|
||||
this.curFace = 1;
|
||||
} else if ("AltName".equals(key)) {
|
||||
face.setAltName(value);
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -648,6 +703,11 @@ public final class CardRules implements ICardCharacteristics {
|
||||
}
|
||||
break;
|
||||
|
||||
case 'F':
|
||||
if("FlavorName".equals(key)) {
|
||||
face.setFlavorName(value);
|
||||
}
|
||||
|
||||
case 'H':
|
||||
if ("HandLifeModifier".equals(key)) {
|
||||
handLife = value;
|
||||
|
||||
@@ -141,7 +141,7 @@ public final class CardRulesPredicates {
|
||||
* @return the predicate
|
||||
*/
|
||||
public static Predicate<CardRules> hasKeyword(final String keyword) {
|
||||
return card -> IterableUtil.any(card.getAllFaces(), cf -> cf != null && card.hasStartOfKeyword(keyword, cf));
|
||||
return card -> IterableUtil.any(card.getAllFaces(), cf -> card.hasStartOfKeyword(keyword, cf));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -325,12 +325,19 @@ public final class CardRulesPredicates {
|
||||
return false;
|
||||
}
|
||||
if (face.hasFunctionalVariants()) {
|
||||
//Couple quirks here - an ICardFace doesn't have a specific variant, so they all need to be checked.
|
||||
//This means text matching the rules of one variant will match prints with any variant. In the case of
|
||||
//flavor names though, we exclude their oracle modified text from matching, so that searching a flavor
|
||||
//name will return only the card matching that name.
|
||||
//TODO: Fix all that someday by doing rules searches by the PaperCard rather than the CardRules.
|
||||
for (Map.Entry<String, ? extends ICardFace> v : face.getFunctionalVariants().entrySet()) {
|
||||
//Not a very pretty implementation, but an ICardFace doesn't have a specific variant, so they all need to be checked.
|
||||
String origOracle = v.getValue().getOracleText();
|
||||
ICardFace vFace = v.getValue();
|
||||
if(vFace.getFlavorName() != null)
|
||||
continue;
|
||||
String origOracle = vFace.getOracleText();
|
||||
if(op(origOracle, operand))
|
||||
return true;
|
||||
String name = v.getValue().getName() + " $" + v.getKey();
|
||||
String name = vFace.getFlavorName() != null ? vFace.getFlavorName() : vFace.getName() + " $" + v.getKey();
|
||||
if(op(CardTranslation.getTranslatedOracle(name), operand))
|
||||
return true;
|
||||
}
|
||||
@@ -346,10 +353,11 @@ public final class CardRulesPredicates {
|
||||
}
|
||||
if (face.hasFunctionalVariants()) {
|
||||
for (Map.Entry<String, ? extends ICardFace> v : face.getFunctionalVariants().entrySet()) {
|
||||
String origType = v.getValue().getType().toString();
|
||||
ICardFace vFace = v.getValue();
|
||||
String origType = vFace.getType().toString();
|
||||
if(op(origType, operand))
|
||||
return true;
|
||||
String name = v.getValue().getName() + " $" + v.getKey();
|
||||
String name = vFace.getFlavorName() != null ? vFace.getFlavorName() : vFace.getName() + " $" + v.getKey();
|
||||
if(op(CardTranslation.getTranslatedType(name, origType), operand))
|
||||
return true;
|
||||
}
|
||||
@@ -363,7 +371,7 @@ public final class CardRulesPredicates {
|
||||
switch (this.field) {
|
||||
case NAME:
|
||||
for (ICardFace face : card.getAllFaces()) {
|
||||
if (face != null && checkName(face.getName())) {
|
||||
if (checkName(face.getName())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
package forge.card;
|
||||
|
||||
import forge.card.CardFace.FaceSelectionMethod;
|
||||
|
||||
import java.util.EnumSet;
|
||||
|
||||
public enum CardSplitType
|
||||
@@ -41,4 +39,10 @@ public enum CardSplitType
|
||||
public CardStateName getChangedStateName() {
|
||||
return changedStateName;
|
||||
}
|
||||
|
||||
public enum FaceSelectionMethod {
|
||||
USE_ACTIVE_FACE,
|
||||
USE_PRIMARY_FACE,
|
||||
COMBINE
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ import java.util.Map;
|
||||
*
|
||||
*/
|
||||
public interface ICardFace extends ICardCharacteristics, ICardRawAbilites, Comparable<ICardFace> {
|
||||
String getAltName();
|
||||
String getFlavorName();
|
||||
|
||||
boolean hasFunctionalVariants();
|
||||
ICardFace getFunctionalVariant(String variant);
|
||||
|
||||
@@ -406,7 +406,7 @@ public enum DeckFormat {
|
||||
final CardPool allCards = deck.getAllCardsInASinglePool(hasCommander());
|
||||
|
||||
// Should group all cards by name, so that different editions of same card are really counted as the same card
|
||||
for (final Entry<String, Integer> cp : Aggregates.groupSumBy(allCards, pc -> StaticData.instance().getCommonCards().getName(pc.getName(), true))) {
|
||||
for (final Entry<String, Integer> cp : Aggregates.groupSumBy(allCards, pc -> StaticData.instance().getCommonCards().getNormalizedName(pc.getName()))) {
|
||||
IPaperCard simpleCard = StaticData.instance().getCommonCards().getCard(cp.getKey());
|
||||
if (simpleCard != null && simpleCard.getRules().isCustom() && !allowCustomCards())
|
||||
return TextUtil.concatWithSpace("contains a Custom Card:", cp.getKey(), "\nPlease Enable Custom Cards in Forge Preferences to use this deck.");
|
||||
|
||||
@@ -6,6 +6,7 @@ import forge.card.ColorSet;
|
||||
import forge.card.ICardFace;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
|
||||
public interface IPaperCard extends InventoryItem, Serializable {
|
||||
|
||||
@@ -31,6 +32,7 @@ public interface IPaperCard extends InventoryItem, Serializable {
|
||||
boolean hasBackFace();
|
||||
ICardFace getMainFace();
|
||||
ICardFace getOtherFace();
|
||||
List<ICardFace> getAllFaces();
|
||||
String getCardImageKey();
|
||||
String getCardAltImageKey();
|
||||
String getCardWSpecImageKey();
|
||||
@@ -43,9 +45,10 @@ public interface IPaperCard extends InventoryItem, Serializable {
|
||||
|
||||
@Override
|
||||
default String getTranslationKey() {
|
||||
if(!NO_FUNCTIONAL_VARIANT.equals(getFunctionalVariant()))
|
||||
//Cards with flavor names will use that flavor name as their translation key. Other variants are just appended as a suffix.
|
||||
if(!NO_FUNCTIONAL_VARIANT.equals(getFunctionalVariant()) && getAllFaces().stream().noneMatch(pc -> pc.getFlavorName() != null))
|
||||
return getName() + " $" + getFunctionalVariant();
|
||||
return getName();
|
||||
return getDisplayName();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -27,6 +27,21 @@ public interface InventoryItem extends ITranslatable {
|
||||
String getItemType();
|
||||
String getImageKey(boolean altState);
|
||||
|
||||
/**
|
||||
* Supplies the user-facing name of this item. Usually the same as `getName()`, but may be overwritten in cases such
|
||||
* as flavor names for cards.
|
||||
*/
|
||||
default String getDisplayName() {
|
||||
return getName();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if this item's display name is different from its actual name. False otherwise.
|
||||
*/
|
||||
default boolean hasFlavorName() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
default String getUntranslatedType() {
|
||||
return getItemType();
|
||||
|
||||
@@ -20,10 +20,7 @@ package forge.item;
|
||||
import forge.ImageKeys;
|
||||
import forge.StaticData;
|
||||
import forge.card.*;
|
||||
import forge.util.CardTranslation;
|
||||
import forge.util.ImageUtil;
|
||||
import forge.util.Localizer;
|
||||
import forge.util.TextUtil;
|
||||
import forge.util.*;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import java.io.*;
|
||||
@@ -56,7 +53,6 @@ public class PaperCard implements Comparable<IPaperCard>, InventoryItemFromSet,
|
||||
private final int artIndex;
|
||||
private final boolean foil;
|
||||
private final PaperCardFlags flags;
|
||||
private final String sortableName;
|
||||
private final String functionalVariant;
|
||||
|
||||
// Calculated fields are below:
|
||||
@@ -64,6 +60,9 @@ public class PaperCard implements Comparable<IPaperCard>, InventoryItemFromSet,
|
||||
// Reference to a new instance of Self, but foiled!
|
||||
private transient PaperCard foiledVersion, noSellVersion, flaglessVersion;
|
||||
private transient Boolean hasImage;
|
||||
private transient String displayName;
|
||||
private transient String sortableName;
|
||||
private transient boolean hasFlavorName;
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
@@ -252,10 +251,12 @@ public class PaperCard implements Comparable<IPaperCard>, InventoryItemFromSet,
|
||||
this.rarity = rarity;
|
||||
this.artist = artist;
|
||||
this.collectorNumber = (collectorNumber != null && !collectorNumber.isEmpty()) ? collectorNumber : IPaperCard.NO_COLLECTOR_NUMBER;
|
||||
this.functionalVariant = functionalVariant != null ? functionalVariant : IPaperCard.NO_FUNCTIONAL_VARIANT;
|
||||
this.displayName = rules.getDisplayNameForVariant(functionalVariant);
|
||||
this.hasFlavorName = !name.equals(displayName);
|
||||
// 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(rules.getName()));
|
||||
this.functionalVariant = functionalVariant != null ? functionalVariant : IPaperCard.NO_FUNCTIONAL_VARIANT;
|
||||
this.sortableName = TextUtil.toSortableName(CardTranslation.getTranslatedName(displayName));
|
||||
|
||||
if(flags == null || flags.equals(PaperCardFlags.IDENTITY_FLAGS))
|
||||
this.flags = PaperCardFlags.IDENTITY_FLAGS;
|
||||
@@ -313,6 +314,67 @@ public class PaperCard implements Comparable<IPaperCard>, InventoryItemFromSet,
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDisplayName() {
|
||||
return this.displayName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasFlavorName() {
|
||||
return this.hasFlavorName;
|
||||
}
|
||||
|
||||
private transient Set<String> searchableNames = null;
|
||||
private transient String searchableNameLang = null;
|
||||
|
||||
public Set<String> getAllSearchableNames() {
|
||||
if(this.searchableNames != null && CardTranslation.getLanguageSelected().equals(searchableNameLang))
|
||||
return searchableNames;
|
||||
if(searchableNameLang != null) //Changed the language. May as well update this.
|
||||
sortableName = TextUtil.toSortableName(CardTranslation.getTranslatedName(displayName));
|
||||
searchableNameLang = CardTranslation.getLanguageSelected();
|
||||
searchableNames = computeSearchableNames(searchableNameLang);
|
||||
return searchableNames;
|
||||
}
|
||||
|
||||
private Set<String> computeSearchableNames(String language) {
|
||||
ICardFace otherFace = this.getOtherFace();
|
||||
if(otherFace == null && NO_FUNCTIONAL_VARIANT.equals(this.functionalVariant))
|
||||
{
|
||||
//99% of cases will land here. This could possibly be optimized further by computing and storing this on
|
||||
//the CardRules instead, but flavor names will still need to work per-print, or at least per-variant.
|
||||
if("en-US".equals(language))
|
||||
return Set.of(this.name);
|
||||
else {
|
||||
String translatedName = CardTranslation.getTranslatedName(this.name);
|
||||
return Set.of(this.name, translatedName, StringUtils.stripAccents(translatedName));
|
||||
}
|
||||
}
|
||||
Set<String> names = new HashSet<>();
|
||||
ICardFace mainFace = this.getMainFace();
|
||||
names.add(mainFace.getName());
|
||||
String mainFlavor = mainFace.getFlavorName();
|
||||
if(mainFlavor != null)
|
||||
names.add(mainFlavor);
|
||||
if(otherFace != null) {
|
||||
names.add(otherFace.getName());
|
||||
String otherFlavor = otherFace.getFlavorName();
|
||||
if(otherFlavor != null)
|
||||
names.add(otherFlavor);
|
||||
|
||||
names.add(mainFace.getName() + " // " + otherFace.getName());
|
||||
if(mainFlavor != null && otherFlavor != null)
|
||||
names.add(mainFlavor + " // " + otherFlavor);
|
||||
}
|
||||
if(!"en-US".equals(language)) {
|
||||
Set<String> translated = names.stream().map(CardTranslation::getTranslatedName).filter(Objects::nonNull).collect(Collectors.toSet());
|
||||
names.addAll(translated);
|
||||
}
|
||||
Set<String> noAccents = names.stream().map(StringUtils::stripAccents).collect(Collectors.toSet());
|
||||
names.addAll(noAccents);
|
||||
return names;
|
||||
}
|
||||
|
||||
/*
|
||||
* This (utility) method transform a collectorNumber String into a key string for sorting.
|
||||
* This method proxies the same strategy implemented in CardEdition.CardInSet class from which the
|
||||
@@ -383,6 +445,9 @@ public class PaperCard implements Comparable<IPaperCard>, InventoryItemFromSet,
|
||||
}
|
||||
rules = pc.getRules();
|
||||
rarity = pc.getRarity();
|
||||
displayName = pc.getDisplayName();
|
||||
hasFlavorName = pc.hasFlavorName();
|
||||
sortableName = TextUtil.toSortableName(CardTranslation.getTranslatedName(displayName));
|
||||
}
|
||||
|
||||
private IPaperCard readObjectAlternate(String name, String edition) throws ClassNotFoundException, IOException {
|
||||
@@ -516,9 +581,16 @@ public class PaperCard implements Comparable<IPaperCard>, InventoryItemFromSet,
|
||||
@Override
|
||||
public ICardFace getOtherFace() {
|
||||
ICardFace face = this.rules.getOtherPart();
|
||||
if(face == null)
|
||||
return null;
|
||||
return this.getVariantForFace(face);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ICardFace> getAllFaces() {
|
||||
return StreamUtil.stream(this.rules.getAllFaces()).map(this::getVariantForFace).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private ICardFace getVariantForFace(ICardFace face) {
|
||||
if(!face.hasFunctionalVariants() || this.functionalVariant.equals(NO_FUNCTIONAL_VARIANT))
|
||||
return face;
|
||||
|
||||
@@ -42,6 +42,10 @@ public abstract class PaperCardPredicates {
|
||||
return new PredicatePrintedWithRarity(rarity);
|
||||
}
|
||||
|
||||
public static Predicate<PaperCard> searchableName(final PredicateString.StringOp op, final String what) {
|
||||
return new PredicateSearchableName(op, what);
|
||||
}
|
||||
|
||||
public static Predicate<PaperCard> name(final String what) {
|
||||
return new PredicateName(what);
|
||||
}
|
||||
@@ -184,6 +188,20 @@ public abstract class PaperCardPredicates {
|
||||
}
|
||||
}
|
||||
|
||||
private static final class PredicateSearchableName extends PredicateString<PaperCard> {
|
||||
private final String operand;
|
||||
|
||||
PredicateSearchableName(final StringOp operator, final String operand) {
|
||||
super(operator);
|
||||
this.operand = operand;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean test(PaperCard paperCard) {
|
||||
return paperCard.getAllSearchableNames().stream().anyMatch(name -> this.op(name, this.operand));
|
||||
}
|
||||
}
|
||||
|
||||
private static final class PredicateName extends PredicateString<PaperCard> {
|
||||
private final String operand;
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ import forge.util.MyRandom;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
public class PaperToken implements InventoryItemFromSet, IPaperCard {
|
||||
@@ -88,6 +89,11 @@ public class PaperToken implements InventoryItemFromSet, IPaperCard {
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDisplayName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return name;
|
||||
@@ -169,6 +175,11 @@ public class PaperToken implements InventoryItemFromSet, IPaperCard {
|
||||
return this.getRules().getOtherPart();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ICardFace> getAllFaces() {
|
||||
return this.cardRules.getAllFaces();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isToken() {
|
||||
return true;
|
||||
|
||||
@@ -258,6 +258,10 @@ public class CardTranslation {
|
||||
return translations;
|
||||
}
|
||||
|
||||
public static String getLanguageSelected() {
|
||||
return languageSelected;
|
||||
}
|
||||
|
||||
private static boolean needsTranslation() {
|
||||
return !languageSelected.equals("en-US");
|
||||
}
|
||||
|
||||
@@ -185,6 +185,8 @@ public class ImageUtil {
|
||||
}
|
||||
} else if (CardSplitType.Split == cp.getRules().getSplitType()) {
|
||||
return card.getMainPart().getName() + card.getOtherPart().getName();
|
||||
} else if (cp.hasFlavorName()) {
|
||||
return cp.getDisplayName();
|
||||
} else if (!IPaperCard.NO_FUNCTIONAL_VARIANT.equals(cp.getFunctionalVariant())) {
|
||||
return cp.getName() + " " + cp.getFunctionalVariant();
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package forge.util;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Predicate;
|
||||
@@ -19,6 +20,8 @@ public class IterableUtil {
|
||||
* which requires the subject to match each of the component predicates.
|
||||
*/
|
||||
public static <T> Predicate<T> and(Iterable<? extends Predicate<? super T>> components) {
|
||||
if(components instanceof List && ((List<?>) components).size() == 1)
|
||||
return ((List<? extends Predicate<? super T>>) components).get(0)::test;
|
||||
return x -> all(components, i -> i.test(x));
|
||||
}
|
||||
|
||||
@@ -27,6 +30,8 @@ public class IterableUtil {
|
||||
* which requires the subject to match at least one of the component predicates.
|
||||
*/
|
||||
public static <T> Predicate<T> or(Iterable<? extends Predicate<? super T>> components) {
|
||||
if(components instanceof List && ((List<?>) components).size() == 1)
|
||||
return ((List<? extends Predicate<? super T>>) components).get(0)::test;
|
||||
return x -> any(components, i -> i.test(x));
|
||||
}
|
||||
|
||||
|
||||
@@ -271,7 +271,7 @@ public class GameFormat implements Comparable<GameFormat> {
|
||||
if (erroneousCI.size() > 0) {
|
||||
final StringBuilder sb = new StringBuilder("contains the following illegal cards:\n");
|
||||
for (final PaperCard cp : erroneousCI) {
|
||||
sb.append("\n").append(cp.getName());
|
||||
sb.append("\n").append(cp.getDisplayName());
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
@@ -290,7 +290,7 @@ public class GameFormat implements Comparable<GameFormat> {
|
||||
if (erroneousRestricted.size() > 0) {
|
||||
final StringBuilder sb = new StringBuilder("contains more than one copy of the following restricted cards:\n");
|
||||
for (final PaperCard cp : erroneousRestricted) {
|
||||
sb.append("\n").append(cp.getName());
|
||||
sb.append("\n").append(cp.getDisplayName());
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
@@ -91,10 +91,10 @@ public class AlterAttributeEffect extends SpellAbilityEffect {
|
||||
}
|
||||
p.addCommander(gameCard);
|
||||
//Seems important enough to mention in the game log.
|
||||
gameCard.getGame().getGameLog().add(GameLogEntryType.STACK_RESOLVE, String.format("%s is now %s's commander.", gameCard.getPaperCard().getName(), p));
|
||||
gameCard.getGame().getGameLog().add(GameLogEntryType.STACK_RESOLVE, String.format("%s is now %s's commander.", gameCard.getPaperCard().getDisplayName(), p));
|
||||
} else {
|
||||
p.removeCommander(gameCard);
|
||||
gameCard.getGame().getGameLog().add(GameLogEntryType.STACK_RESOLVE, String.format("%s is no longer %s's commander.", gameCard.getPaperCard().getName(), p));
|
||||
gameCard.getGame().getGameLog().add(GameLogEntryType.STACK_RESOLVE, String.format("%s is no longer %s's commander.", gameCard.getPaperCard().getDisplayName(), p));
|
||||
}
|
||||
altered = true;
|
||||
break;
|
||||
|
||||
@@ -952,23 +952,28 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars, ITr
|
||||
|
||||
@Override
|
||||
public final String getName() {
|
||||
return getName(currentState, false);
|
||||
return getName(currentState);
|
||||
}
|
||||
|
||||
public final String getName(boolean alt) {
|
||||
return getName(currentState, alt);
|
||||
}
|
||||
public final String getName(CardStateName stateName) {
|
||||
return getName(getState(stateName), false);
|
||||
}
|
||||
public final String getName(CardState state, boolean alt) {
|
||||
public final String getName(CardState state) {
|
||||
String name = state.getName();
|
||||
for (CardChangedName change : this.changedCardNames.values()) {
|
||||
if (change.isOverwrite()) {
|
||||
name = change.newName();
|
||||
}
|
||||
}
|
||||
return alt ? StaticData.instance().getCommonCards().getName(name, true) : name;
|
||||
return name;
|
||||
}
|
||||
|
||||
public final String getDisplayName() {
|
||||
return getDisplayName(currentState);
|
||||
}
|
||||
|
||||
public final String getDisplayName(CardState state) {
|
||||
//If this card has a changed name, don't use flavor names.
|
||||
if(state.getFlavorName() == null || hasNameOverwrite())
|
||||
return getName(state);
|
||||
return state.getFlavorName();
|
||||
}
|
||||
|
||||
public final boolean hasNameOverwrite() {
|
||||
@@ -6058,7 +6063,7 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars, ITr
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return sharesNameWith(c1.getName(true));
|
||||
return sharesNameWith(c1.getName());
|
||||
}
|
||||
|
||||
public final boolean sharesNameWith(final String name) {
|
||||
@@ -6067,7 +6072,7 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars, ITr
|
||||
return false;
|
||||
}
|
||||
|
||||
boolean shares = getName(true).equals(name);
|
||||
boolean shares = getName().equals(name);
|
||||
|
||||
// Split cards has extra logic to check if it does share a name with
|
||||
if (!shares && !hasNameOverwrite()) {
|
||||
@@ -7844,7 +7849,7 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars, ITr
|
||||
}
|
||||
@Override
|
||||
public String getUntranslatedName() {
|
||||
return this.getName();
|
||||
return this.getDisplayName();
|
||||
}
|
||||
@Override
|
||||
public String getUntranslatedType() {
|
||||
|
||||
@@ -402,6 +402,8 @@ public class CardFactory {
|
||||
|
||||
c.getCurrentState().setOracleText(face.getOracleText());
|
||||
|
||||
c.getCurrentState().setFlavorName(face.getFlavorName());
|
||||
|
||||
// Super and 'middle' types should use enums.
|
||||
c.setType(new CardType(face.getType()));
|
||||
|
||||
|
||||
@@ -63,6 +63,7 @@ public class CardState implements GameObject, IHasSVars, ITranslatable {
|
||||
private ColorSet color = ColorSet.C;
|
||||
private String oracleText = "";
|
||||
private String functionalVariantName = null;
|
||||
private String flavorName = null;
|
||||
private int basePower = 0;
|
||||
private int baseToughness = 0;
|
||||
private String basePowerString = null;
|
||||
@@ -221,6 +222,15 @@ public class CardState implements GameObject, IHasSVars, ITranslatable {
|
||||
view.setFunctionalVariantName(functionalVariantName);
|
||||
}
|
||||
|
||||
public String getFlavorName() {
|
||||
return flavorName;
|
||||
}
|
||||
|
||||
public void setFlavorName(String flavorName) {
|
||||
this.flavorName = flavorName;
|
||||
view.updateName(this);
|
||||
}
|
||||
|
||||
public final int getBasePower() {
|
||||
return basePower;
|
||||
}
|
||||
@@ -716,6 +726,7 @@ public class CardState implements GameObject, IHasSVars, ITranslatable {
|
||||
setBaseLoyalty(source.getBaseLoyalty());
|
||||
setBaseDefense(source.getBaseDefense());
|
||||
setAttractionLights(source.getAttractionLights());
|
||||
setFlavorName(source.getFlavorName());
|
||||
setSVars(source.getSVars());
|
||||
|
||||
abilities.clear();
|
||||
@@ -930,9 +941,10 @@ public class CardState implements GameObject, IHasSVars, ITranslatable {
|
||||
|
||||
@Override
|
||||
public String getTranslationKey() {
|
||||
String displayName = flavorName == null ? name : flavorName;
|
||||
if(StringUtils.isNotEmpty(functionalVariantName))
|
||||
return name + " $" + functionalVariantName;
|
||||
return name;
|
||||
return displayName + " $" + functionalVariantName;
|
||||
return displayName;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -7,10 +7,7 @@ import forge.ImageKeys;
|
||||
import forge.StaticData;
|
||||
import forge.card.*;
|
||||
import forge.card.mana.ManaCost;
|
||||
import forge.game.Direction;
|
||||
import forge.game.EvenOdd;
|
||||
import forge.game.GameEntityView;
|
||||
import forge.game.GameType;
|
||||
import forge.game.*;
|
||||
import forge.game.combat.Combat;
|
||||
import forge.game.keyword.Keyword;
|
||||
import forge.game.player.Player;
|
||||
@@ -100,6 +97,25 @@ public class CardView extends GameEntityView {
|
||||
set(TrackableProperty.Controller, ownerAndController);
|
||||
set(TrackableProperty.ImageKey, imageKey);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void updateName(GameEntity e) {
|
||||
//Name reflects the current display name, as modified by any flavor names.
|
||||
//OracleName can be used to find the true name of a card.
|
||||
if (e instanceof Card c) {
|
||||
set(TrackableProperty.Name, c.getDisplayName());
|
||||
set(TrackableProperty.OracleName, c.getName());
|
||||
}
|
||||
else {
|
||||
super.updateName(e);
|
||||
set(TrackableProperty.OracleName, e.getName());
|
||||
}
|
||||
}
|
||||
|
||||
public String getOracleName() {
|
||||
return get(TrackableProperty.OracleName);
|
||||
}
|
||||
|
||||
public PlayerView getOwner() {
|
||||
return get(TrackableProperty.Owner);
|
||||
}
|
||||
@@ -1280,16 +1296,26 @@ public class CardView extends GameEntityView {
|
||||
}
|
||||
void updateName(CardState c) {
|
||||
Card card = c.getCard();
|
||||
setName(card.getName(c, false));
|
||||
setName(card.getDisplayName(c));
|
||||
setOracleName(card.getName(c));
|
||||
|
||||
if (CardView.this.getCurrentState() == this) {
|
||||
if (card != null) {
|
||||
CardView.this.updateName(card);
|
||||
}
|
||||
}
|
||||
private void setName(String name) {
|
||||
set(TrackableProperty.Name, name);
|
||||
}
|
||||
private void setName(String name0) {
|
||||
set(TrackableProperty.Name, name0);
|
||||
|
||||
/**
|
||||
* @return The name of the card, unaltered by flavor names.
|
||||
*/
|
||||
public String getOracleName() {
|
||||
return get(TrackableProperty.OracleName);
|
||||
}
|
||||
|
||||
private void setOracleName(String name) {
|
||||
set(TrackableProperty.OracleName, name);
|
||||
}
|
||||
|
||||
public ColorSet getColors() {
|
||||
|
||||
@@ -131,6 +131,7 @@ public enum TrackableProperty {
|
||||
FunctionalVariant(TrackableTypes.StringType),
|
||||
OracleText(TrackableTypes.StringType),
|
||||
RulesText(TrackableTypes.StringType),
|
||||
OracleName(TrackableTypes.StringType),
|
||||
Power(TrackableTypes.IntegerType),
|
||||
Toughness(TrackableTypes.IntegerType),
|
||||
Loyalty(TrackableTypes.StringType),
|
||||
|
||||
@@ -142,7 +142,7 @@ public class CardDetailPanel extends SkinnedPanel {
|
||||
}
|
||||
|
||||
public final void setItem(final InventoryItemFromSet item) {
|
||||
nameCostLabel.setText(item.getName());
|
||||
nameCostLabel.setText(item.getDisplayName());
|
||||
typeLabel.setVisible(false);
|
||||
powerToughnessLabel.setVisible(false);
|
||||
idLabel.setText("");
|
||||
|
||||
@@ -90,7 +90,7 @@ public class CardListChooser extends FDialog {
|
||||
public void windowClosing(final WindowEvent e) {
|
||||
//CardTranslation.getTranslatedName
|
||||
if (FOptionPane.showConfirmDialog(
|
||||
Localizer.getInstance().getMessage("lblAreYouSureWantPickCard", CardTranslation.getTranslatedName(jList.getSelectedValue().getName())),
|
||||
Localizer.getInstance().getMessage("lblAreYouSureWantPickCard", CardTranslation.getTranslatedName(jList.getSelectedValue().getDisplayName())),
|
||||
Localizer.getInstance().getMessage("lblSelectThisCardConfirm"), false)
|
||||
) {
|
||||
dispose();
|
||||
|
||||
@@ -1215,7 +1215,7 @@ public class ImageView<T extends InventoryItem> extends ItemView<T> {
|
||||
g.setColor(Color.white);
|
||||
Shape clip = g.getClip();
|
||||
g.setClip(bounds);
|
||||
g.drawString(item.getName(), bounds.x + 10, bounds.y + 20);
|
||||
g.drawString(item.getDisplayName(), bounds.x + 10, bounds.y + 20);
|
||||
g.setClip(clip);
|
||||
}
|
||||
|
||||
|
||||
@@ -102,11 +102,11 @@ public class StarRenderer extends ItemCellRenderer {
|
||||
return;
|
||||
}
|
||||
if (favorite == 0) {
|
||||
this.setToolTipText(localizer.getMessage("lblClickToAddTargetToFavorites", CardTranslation.getTranslatedName(card.getName())));
|
||||
this.setToolTipText(localizer.getMessage("lblClickToAddTargetToFavorites", CardTranslation.getTranslatedName(card.getDisplayName())));
|
||||
skinImage = FSkin.getImage(FSkinProp.IMG_STAR_OUTLINE);
|
||||
}
|
||||
else { //TODO: consider supporting more than 1 star
|
||||
this.setToolTipText(localizer.getMessage("lblClickToRemoveTargetToFavorites", CardTranslation.getTranslatedName(card.getName())));
|
||||
this.setToolTipText(localizer.getMessage("lblClickToRemoveTargetToFavorites", CardTranslation.getTranslatedName(card.getDisplayName())));
|
||||
skinImage = FSkin.getImage(FSkinProp.IMG_STAR_FILLED);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -622,7 +622,7 @@ public class DeckImport<TModel extends DeckBase> extends FDialog {
|
||||
cardPreviewLabel.setText(String.format("<html>%s %s<br>%s</html>", STYLESHEET, editionLbl, statusLbl));
|
||||
|
||||
// set tooltip
|
||||
String tooltip = String.format("%s [%s] #%s", card.getName(), card.getEdition(),
|
||||
String tooltip = String.format("%s [%s] #%s", card.getDisplayName(), card.getEdition(),
|
||||
card.getCollectorNumber());
|
||||
cardImagePreview.setToolTipText(tooltip);
|
||||
}
|
||||
|
||||
@@ -524,7 +524,7 @@ public class VLobby implements ILobbyView {
|
||||
PaperCard vanguardAvatar = null;
|
||||
final Deck deck = decks[playerIndex];
|
||||
if (selected instanceof PaperCard) {
|
||||
pp.setVanguardButtonText(((PaperCard) selected).getName());
|
||||
pp.setVanguardButtonText(((PaperCard) selected).getDisplayName());
|
||||
cdp.setCard(CardView.getCardForUi((PaperCard) selected));
|
||||
cdp.setVisible(true);
|
||||
refreshPanels(false, true);
|
||||
|
||||
@@ -1438,8 +1438,8 @@ public final class CMatchUI
|
||||
private int getRotation(CardView cardView) {
|
||||
final int rotation;
|
||||
if (cardView.isSplitCard()) {
|
||||
String cardName = cardView.getName();
|
||||
if (cardName.isEmpty()) { cardName = cardView.getAlternateState().getName(); }
|
||||
String cardName = cardView.getOracleName();
|
||||
if (cardName.isEmpty()) { cardName = cardView.getAlternateState().getOracleName(); }
|
||||
|
||||
PaperCard pc = StaticData.instance().getCommonCards().getCard(cardName);
|
||||
boolean hasKeywordAftermath = pc != null && Card.getCardForUi(pc).hasKeyword(Keyword.AFTERMATH);
|
||||
|
||||
@@ -797,7 +797,7 @@ public class FCardImageRenderer {
|
||||
if (state.isBasicLand()) {
|
||||
//draw icons for basic lands
|
||||
String imageKey;
|
||||
switch (state.getName().replaceFirst("^Snow-Covered ", "")) {
|
||||
switch (state.getOracleName().replaceFirst("^Snow-Covered ", "")) {
|
||||
case "Plains":
|
||||
imageKey = "W";
|
||||
break;
|
||||
|
||||
@@ -230,8 +230,8 @@ public enum CardZoomer {
|
||||
return 0;
|
||||
}
|
||||
if (thisCard.getCard().isSplitCard()) {
|
||||
String cardName = thisCard.getCard().getName();
|
||||
if (cardName.isEmpty()) { cardName = thisCard.getCard().getAlternateState().getName(); }
|
||||
String cardName = thisCard.getCard().getOracleName();
|
||||
if (cardName.isEmpty()) { cardName = thisCard.getCard().getAlternateState().getOracleName(); }
|
||||
|
||||
PaperCard pc = StaticData.instance().getCommonCards().getCard(cardName);
|
||||
boolean isAftermath = pc != null && Card.getCardForUi(pc).hasKeyword(Keyword.AFTERMATH);
|
||||
|
||||
@@ -504,8 +504,8 @@ public class CardPanel extends SkinnedPanel implements CardContainer, IDisposabl
|
||||
} else {
|
||||
if (!card.isFaceDown()) { // no need to draw mana symbols on face down split cards (e.g. manifested)
|
||||
PaperCard pc = null;
|
||||
if (!card.getName().isEmpty()) {
|
||||
pc = StaticData.instance().getCommonCards().getCard(card.getName());
|
||||
if (!card.getOracleName().isEmpty()) {
|
||||
pc = StaticData.instance().getCommonCards().getCard(card.getOracleName());
|
||||
}
|
||||
int ofs = pc != null && Card.getCardForUi(pc).hasKeyword(Keyword.AFTERMATH) ? -12 : 12;
|
||||
|
||||
|
||||
@@ -107,7 +107,7 @@ public class PlayArea extends CardPanelContainer implements CardPanelMouseListen
|
||||
for (int i = 0, n = allLands.size(); i < n; i++) {
|
||||
final CardStack stack = allLands.get(i);
|
||||
final CardPanel firstPanel = stack.get(0);
|
||||
if (firstPanel.getCard().getCurrentState().getName().equals(state.getName())) {
|
||||
if (firstPanel.getCard().getCurrentState().getOracleName().equals(state.getOracleName())) {
|
||||
if (!firstPanel.getAttachedPanels().isEmpty() || firstPanel.getCard().hasCardAttachments()) {
|
||||
// Put this land to the left of lands with the same name
|
||||
// and attachments.
|
||||
@@ -162,7 +162,7 @@ public class PlayArea extends CardPanelContainer implements CardPanelMouseListen
|
||||
final CardPanel firstPanel = stack.get(0);
|
||||
final CardView firstCard = firstPanel.getCard();
|
||||
|
||||
if (firstPanel.getCard().getCurrentState().getName().equals(state.getName())) {
|
||||
if (firstPanel.getCard().getCurrentState().getOracleName().equals(state.getOracleName())) {
|
||||
if (!firstPanel.getAttachedPanels().isEmpty()) {
|
||||
// Put this token to the left of tokens with the same
|
||||
// name and attachments.
|
||||
@@ -220,7 +220,7 @@ public class PlayArea extends CardPanelContainer implements CardPanelMouseListen
|
||||
final CardStack stack = allCreatures.get(i);
|
||||
final CardPanel firstPanel = stack.get(0);
|
||||
final CardView firstCard = firstPanel.getCard();
|
||||
if (firstCard.getName().equals(card.getName())) {
|
||||
if (firstCard.getOracleName().equals(card.getOracleName())) {
|
||||
if (!firstPanel.getAttachedPanels().isEmpty()) {
|
||||
// Put this creature to the left of creatures with the same
|
||||
// name and attachments.
|
||||
@@ -335,7 +335,7 @@ public class PlayArea extends CardPanelContainer implements CardPanelMouseListen
|
||||
final CardStateView otherState = otherCard.getCurrentState();
|
||||
final CardView thisCard = panel.getCard();
|
||||
final CardStateView thisState = thisCard.getCurrentState();
|
||||
if (otherState.getName().equals(thisState.getName()) && s.size() < STACK_MAX_OTHERS) {
|
||||
if (otherState.getOracleName().equals(thisState.getOracleName()) && s.size() < STACK_MAX_OTHERS) {
|
||||
if (panel.getAttachedPanels().isEmpty()
|
||||
&& thisCard.hasSameCounters(otherCard)
|
||||
&& (thisCard.isSick() == otherCard.isSick())
|
||||
|
||||
@@ -993,7 +993,7 @@ public class RewardActor extends Actor implements Disposable, ImageFetcher.Callb
|
||||
Reward.Type rewardType = reward.getType();
|
||||
switch (rewardType) {
|
||||
case Card:
|
||||
display = reward.getCard() != null ? CardTranslation.getTranslatedName(reward.getCard().getName()) : "";
|
||||
display = reward.getCard() != null ? CardTranslation.getTranslatedName(reward.getCard().getDisplayName()) : "";
|
||||
//alignment = Align.topLeft;
|
||||
labelStyle = "dialog";
|
||||
break;
|
||||
|
||||
@@ -219,7 +219,7 @@ public class CardZoom extends FOverlay {
|
||||
}
|
||||
if (item instanceof InventoryItem) {
|
||||
InventoryItem ii = (InventoryItem)item;
|
||||
return new CardView(-1, null, ii.getName(), null, ii.getImageKey(false));
|
||||
return new CardView(-1, null, ii.getDisplayName(), null, ii.getImageKey(false));
|
||||
}
|
||||
return new CardView(-1, null, item.toString());
|
||||
}
|
||||
|
||||
@@ -1866,7 +1866,7 @@ public class FDeckEditor extends TabPageScreen<FDeckEditor> {
|
||||
sortedOptions.add(option);
|
||||
}
|
||||
}
|
||||
GuiChoose.oneOrNone(Forge.getLocalizer().getMessage("lblSelectPreferredArt") + " " + card.getName(), sortedOptions, result -> {
|
||||
GuiChoose.oneOrNone(Forge.getLocalizer().getMessage("lblSelectPreferredArt") + " " + card.getDisplayName(), sortedOptions, result -> {
|
||||
if (result != null) {
|
||||
if (result != card) {
|
||||
cardManager.replaceAll(card, result);
|
||||
@@ -2104,7 +2104,7 @@ public class FDeckEditor extends TabPageScreen<FDeckEditor> {
|
||||
}
|
||||
final Localizer localizer = Forge.getLocalizer();
|
||||
String lblReplaceCard = localizer.getMessage("lblReplace");
|
||||
String prompt = localizer.getMessage("lblSelectReplacementCard") + " " + card.getName();
|
||||
String prompt = localizer.getMessage("lblSelectReplacementCard") + " " + card.getDisplayName();
|
||||
String promptQuantity = String.format("%s - %s %s", card, lblReplaceCard, localizer.getMessage("lblHowMany"));
|
||||
//First have the player choose which card to swap in.
|
||||
GuiChoose.oneOrNone(prompt, sortedOptions, replacement -> {
|
||||
|
||||
@@ -1251,9 +1251,9 @@ public class ImageView<T extends InventoryItem> extends ItemView<T> {
|
||||
g.drawImage(Forge.getAssets().getTexture(getDefaultSkinFile("cover.png"), false), x + (w - w * scale) / 2, y + (h - h * scale) / 1.5f, w * scale, h * scale);
|
||||
}
|
||||
//fake labelname shadow
|
||||
g.drawText(item.getName(), GROUP_HEADER_FONT, Color.BLACK, (x + PADDING) - 1f, (y + PADDING * 2) + 1f, w - 2 * PADDING, h - 2 * PADDING, true, Align.center, false);
|
||||
g.drawText(item.getDisplayName(), GROUP_HEADER_FONT, Color.BLACK, (x + PADDING) - 1f, (y + PADDING * 2) + 1f, w - 2 * PADDING, h - 2 * PADDING, true, Align.center, false);
|
||||
//labelname
|
||||
g.drawText(item.getName(), GROUP_HEADER_FONT, Color.WHITE, x + PADDING, y + PADDING * 2, w - 2 * PADDING, h - 2 * PADDING, true, Align.center, false);
|
||||
g.drawText(item.getDisplayName(), GROUP_HEADER_FONT, Color.WHITE, x + PADDING, y + PADDING * 2, w - 2 * PADDING, h - 2 * PADDING, true, Align.center, false);
|
||||
} else {
|
||||
if (!deckProxy.isGeneratedDeck()) {
|
||||
if (deckProxy.getDeck().isEmpty()) {
|
||||
@@ -1326,13 +1326,13 @@ public class ImageView<T extends InventoryItem> extends ItemView<T> {
|
||||
String key = item.getImageKey(false);
|
||||
if (key.startsWith(ImageKeys.PRECON_PREFIX) || key.startsWith(ImageKeys.FATPACK_PREFIX)
|
||||
|| key.startsWith(ImageKeys.BOOSTERBOX_PREFIX) || key.startsWith(ImageKeys.BOOSTER_PREFIX) || key.startsWith(ImageKeys.TOURNAMENTPACK_PREFIX)) {
|
||||
CardView cv = new CardView(-1, null, item.getName(), null, item.getImageKey(false));
|
||||
CardView cv = new CardView(-1, null, item.getDisplayName(), null, item.getImageKey(false));
|
||||
CardImageRenderer.drawCardImage(g, cv, false, x, y, w, h, CardStackPosition.Top, false, false);
|
||||
return;
|
||||
}
|
||||
}
|
||||
g.fillRect(Color.BLACK, x, y, w, h);
|
||||
g.drawText(item.getName(), GROUP_HEADER_FONT, Color.WHITE, x + PADDING, y + PADDING, w - 2 * PADDING, h - 2 * PADDING, true, Align.center, false);
|
||||
g.drawText(item.getDisplayName(), GROUP_HEADER_FONT, Color.WHITE, x + PADDING, y + PADDING, w - 2 * PADDING, h - 2 * PADDING, true, Align.center, false);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -777,7 +777,7 @@ public abstract class LobbyScreen extends LaunchScreen implements ILobbyView {
|
||||
CardPool avatarPool = new CardPool();
|
||||
avatarPool.add(playerPanel.getVanguardAvatar());
|
||||
playerDeck.putSection(DeckSection.Avatar, avatarPool);
|
||||
VanguardAvatar = Forge.getLocalizer().getMessage("lblVanguard") + ": " + playerPanel.getVanguardAvatar().getName();
|
||||
VanguardAvatar = Forge.getLocalizer().getMessage("lblVanguard") + ": " + playerPanel.getVanguardAvatar().getDisplayName();
|
||||
playerPanel.setVanguarAvatarName(VanguardAvatar);
|
||||
}
|
||||
|
||||
|
||||
@@ -204,7 +204,7 @@ public class PlayerPanel extends FContainer {
|
||||
});
|
||||
lstVanguardAvatars = new FVanguardChooser(isAi, e -> {
|
||||
btnVanguardAvatar.setText(Forge.getLocalizer().getMessage("lblVanguard")
|
||||
+ ":" + (Forge.isLandscapeMode() ? " " : "\n") + ((CardManager)e.getSource()).getSelectedItem().getName());
|
||||
+ ":" + (Forge.isLandscapeMode() ? " " : "\n") + ((CardManager)e.getSource()).getSelectedItem().getDisplayName());
|
||||
if (allowNetworking && btnVanguardAvatar.isEnabled() && humanAiSwitch.isToggled()) {
|
||||
screen.updateMyDeck(index);
|
||||
}
|
||||
|
||||
@@ -128,12 +128,12 @@ public class VField extends FContainer {
|
||||
if (!this.stackNonTokenCreatures && cardState.isCreature() && !card.isToken()) {
|
||||
return false;
|
||||
}
|
||||
final String cardName = cardState.getName();
|
||||
final String cardName = cardState.getOracleName();
|
||||
for (CardView c : cardsOfType) {
|
||||
CardStateView cState = c.getCurrentState();
|
||||
if (cState.isCreature()) {
|
||||
if (!c.hasCardAttachments() &&
|
||||
cardName.equals(cState.getName()) &&
|
||||
cardName.equals(cState.getOracleName()) &&
|
||||
card.hasSameCounters(c) &&
|
||||
card.hasSamePT(c) && //don't stack token with different PT
|
||||
cardState.getKeywordKey().equals(cState.getKeywordKey()) &&
|
||||
@@ -145,7 +145,7 @@ public class VField extends FContainer {
|
||||
}
|
||||
} else {
|
||||
if (!c.hasCardAttachments() &&
|
||||
cardName.equals(cState.getName()) &&
|
||||
cardName.equals(cState.getOracleName()) &&
|
||||
card.hasSameCounters(c) &&
|
||||
cardState.getKeywordKey().equals(cState.getKeywordKey()) &&
|
||||
cardState.getColors() == cState.getColors() &&
|
||||
|
||||
@@ -130,7 +130,7 @@ public class VReveal extends FDropDown {
|
||||
private RevealEntryDisplay(PaperCard pc, boolean isAltRow) {
|
||||
paperCard = pc;
|
||||
altRow = isAltRow;
|
||||
text = CardTranslation.getTranslatedName(pc.getName()) + "\n" + formatType();
|
||||
text = CardTranslation.getTranslatedName(pc.getDisplayName()) + "\n" + formatType();
|
||||
}
|
||||
|
||||
public float getMinHeight(float width) {
|
||||
|
||||
@@ -202,7 +202,7 @@ public class ConquestCommandersScreen extends FScreen {
|
||||
float imageSize = CardRenderer.MANA_SYMBOL_SIZE;
|
||||
ColorSet cardColor = card.getRules().getColorIdentity();
|
||||
float availableWidth = w - cardArtWidth - CardFaceSymbols.getWidth(cardColor, imageSize) - FList.PADDING;
|
||||
g.drawText(card.getName(), font, foreColor, x, y, availableWidth, imageSize, false, Align.left, true);
|
||||
g.drawText(card.getDisplayName(), font, foreColor, x, y, availableWidth, imageSize, false, Align.left, true);
|
||||
CardFaceSymbols.drawColorSet(g, cardColor, x + availableWidth + FList.PADDING, y, imageSize);
|
||||
|
||||
if (compactModeHandler.isCompactMode()) {
|
||||
|
||||
@@ -684,10 +684,10 @@ public class ConquestMultiverseScreen extends FScreen {
|
||||
float labelHeight = playerAvatar.getTop();
|
||||
|
||||
if (playerAvatar.card != null) {
|
||||
g.drawText(playerAvatar.card.getName(), AVATAR_NAME_FONT, Color.WHITE, PADDING, 0, labelWidth, labelHeight, false, Align.left, true);
|
||||
g.drawText(playerAvatar.card.getDisplayName(), AVATAR_NAME_FONT, Color.WHITE, PADDING, 0, labelWidth, labelHeight, false, Align.left, true);
|
||||
}
|
||||
if (opponentAvatar.card != null) {
|
||||
g.drawText(opponentAvatar.card.getName(), AVATAR_NAME_FONT, Color.WHITE, getWidth() - labelWidth - PADDING, getHeight() - labelHeight, labelWidth, labelHeight, false, Align.right, true);
|
||||
g.drawText(opponentAvatar.card.getDisplayName(), AVATAR_NAME_FONT, Color.WHITE, getWidth() - labelWidth - PADDING, getHeight() - labelHeight, labelWidth, labelHeight, false, Align.right, true);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -282,7 +282,7 @@ public class LoadConquestScreen extends LaunchScreen {
|
||||
font = FSkinFont.get(12);
|
||||
float cardsWidth = font.getBounds(cards).width + iconSize + SettingsScreen.SETTING_PADDING;
|
||||
float shardsWidth = font.getBounds(shards).width + iconSize + SettingsScreen.SETTING_PADDING;
|
||||
g.drawText(value.getPlaneswalker().getName() + " - " + value.getCurrentPlane().getName().replace("_", " "), font, SettingsScreen.DESC_COLOR, x, y, w - shardsWidth - cardsWidth, h, false, Align.left, false);
|
||||
g.drawText(value.getPlaneswalker().getDisplayName() + " - " + value.getCurrentPlane().getName().replace("_", " "), font, SettingsScreen.DESC_COLOR, x, y, w - shardsWidth - cardsWidth, h, false, Align.left, false);
|
||||
g.drawImage(FSkinImage.SPELLBOOK, x + w - shardsWidth - cardsWidth + iconOffset, y - SettingsScreen.SETTING_PADDING, iconSize, iconSize);
|
||||
g.drawText(cards, font, SettingsScreen.DESC_COLOR, x + w - shardsWidth - cardsWidth + iconSize + SettingsScreen.SETTING_PADDING, y, w, h, false, Align.left, false);
|
||||
g.drawImage(FSkinImage.AETHER_SHARD, x + w - shardsWidth + iconOffset, y - SettingsScreen.SETTING_PADDING, iconSize, iconSize);
|
||||
|
||||
@@ -9,7 +9,7 @@ import forge.screens.match.MatchController;
|
||||
public class CardRendererUtils {
|
||||
public static boolean needsRotation(final CardView card) {
|
||||
return needsRotation(card.isSplitCard() ? ForgePreferences.FPref.UI_ROTATE_SPLIT_CARDS
|
||||
: ForgePreferences.FPref.UI_ROTATE_PLANE_OR_PHENOMENON, card, canShowAlternate(card, card.getName()));
|
||||
: ForgePreferences.FPref.UI_ROTATE_PLANE_OR_PHENOMENON, card, canShowAlternate(card, card.getOracleName()));
|
||||
}
|
||||
public static boolean needsRotation(final CardView card, final boolean altState) {
|
||||
return needsRotation(card.isSplitCard() ? ForgePreferences.FPref.UI_ROTATE_SPLIT_CARDS
|
||||
@@ -52,7 +52,7 @@ public class CardRendererUtils {
|
||||
showAlt = card.getAlternateState().getOracleText().contains(reference.trim());
|
||||
else {
|
||||
if (card.isRoom()) // special case for room cards
|
||||
showAlt = card.getAlternateState().getName().equalsIgnoreCase(reference);
|
||||
showAlt = card.getAlternateState().getOracleName().equalsIgnoreCase(reference);
|
||||
else
|
||||
showAlt = reference.contains(card.getAlternateState().getAbilityText());
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
Name:Blanka, Ferocious Friend
|
||||
AltName:The Howling Abomination
|
||||
Variant:UniversesWithin:FlavorName:The Howling Abomination
|
||||
ManaCost:3 R G
|
||||
Types:Legendary Creature Human Beast Warrior
|
||||
PT:5/5
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
Name:Chief Jim Hopper
|
||||
AltName:Sophina, Spearsage Deserter
|
||||
Variant:UniversesWithin:FlavorName:Sophina, Spearsage Deserter
|
||||
ManaCost:2 R W
|
||||
Types:Legendary Creature Human Soldier
|
||||
PT:4/4
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
Name:Chun-Li, Countless Kicks
|
||||
AltName:Zethi, Arcane Blademaster
|
||||
Variant:UniversesWithin:FlavorName:Zethi, Arcane Blademaster
|
||||
ManaCost:1 W U
|
||||
Types:Legendary Creature Human Soldier
|
||||
PT:3/3
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
Name:Daryl, Hunter of Walkers
|
||||
AltName:Hansk, Slayer Zealot
|
||||
Variant:UniversesWithin:FlavorName:Hansk, Slayer Zealot
|
||||
ManaCost:2 R G
|
||||
Types:Legendary Creature Human Archer
|
||||
PT:4/4
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
Name:Dhalsim, Pliable Pacifist
|
||||
AltName:Tadeas, Juniper Ascendant
|
||||
Variant:UniversesWithin:FlavorName:Tadeas, Juniper Ascendant
|
||||
ManaCost:2 G W
|
||||
Types:Legendary Creature Human Monk
|
||||
PT:1/3
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
Name:Doric, Nature's Warden
|
||||
AltName:Casal, Lurkwood Pathfinder
|
||||
Variant:UniversesWithin:FlavorName:Casal, Lurkwood Pathfinder
|
||||
ManaCost:3 G
|
||||
Types:Legendary Creature Tiefling Druid
|
||||
PT:3/3
|
||||
@@ -15,7 +15,7 @@ Oracle:Vigilance\nWhen Doric, Nature's Warden enters, search your library for a
|
||||
ALTERNATE
|
||||
|
||||
Name:Doric, Owlbear Avenger
|
||||
AltName:Casal, Pathbreaker Owlbear
|
||||
Variant:UniversesWithin:FlavorName:Casal, Pathbreaker Owlbear
|
||||
ManaCost:no cost
|
||||
Colors:green
|
||||
Types:Legendary Creature Bird Bear
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
Name:Dustin, Gadget Genius
|
||||
AltName:Hargilde, Kindly Runechanter
|
||||
Variant:UniversesWithin:FlavorName:Hargilde, Kindly Runechanter
|
||||
ManaCost:2 W U
|
||||
Types:Legendary Creature Human
|
||||
PT:2/3
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
Name:E. Honda, Sumo Champion
|
||||
AltName:Baldin, Century Herdmaster
|
||||
Variant:UniversesWithin:FlavorName:Baldin, Century Herdmaster
|
||||
ManaCost:4 W W
|
||||
Types:Legendary Creature Human Warrior
|
||||
PT:0/7
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
Name:Edgin, Larcenous Lutenist
|
||||
AltName:Bohn, Beguiling Balladeer
|
||||
Variant:UniversesWithin:FlavorName:Bohn, Beguiling Balladeer
|
||||
ManaCost:1 U R
|
||||
Types:Legendary Creature Human Bard
|
||||
PT:3/3
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
Name:Eleven, the Mage
|
||||
AltName:Cecily, Haunted Mage
|
||||
Variant:UniversesWithin:FlavorName:Cecily, Haunted Mage
|
||||
ManaCost:1 U B R
|
||||
Types:Legendary Creature Human Wizard
|
||||
PT:3/5
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
Name:Forge, Neverwinter Charlatan
|
||||
AltName:Evin, Waterdeep Opportunist
|
||||
Variant:UniversesWithin:FlavorName:Evin, Waterdeep Opportunist
|
||||
ManaCost:3 B
|
||||
Types:Legendary Creature Human Rogue
|
||||
PT:2/4
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
Name:Glenn, the Voice of Calm
|
||||
AltName:Gregor, Shrewd Magistrate
|
||||
Variant:UniversesWithin:FlavorName:Gregor, Shrewd Magistrate
|
||||
ManaCost:1 W U
|
||||
Types:Legendary Creature Human Advisor
|
||||
PT:1/3
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
Name:Guile, Sonic Soldier
|
||||
AltName:Immard, the Stormcleaver
|
||||
Variant:UniversesWithin:FlavorName:Immard, the Stormcleaver
|
||||
ManaCost:1 U R W
|
||||
Types:Legendary Creature Human Soldier
|
||||
PT:4/4
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
Name:Hawkins National Laboratory
|
||||
AltName:Havengul Laboratory
|
||||
Variant:UniversesWithin:FlavorName:Havengul Laboratory
|
||||
ManaCost:no cost
|
||||
Types:Legendary Land
|
||||
A:AB$ Mana | Cost$ T | Produced$ C | SpellDescription$ Add {C}.
|
||||
@@ -15,7 +15,7 @@ Oracle:{T}: Add {C}.\n{4}, {T}: Investigate.\nAt the beginning of your end step,
|
||||
ALTERNATE
|
||||
|
||||
Name:The Upside Down
|
||||
AltName:Havengul Mystery
|
||||
Variant:UniversesWithin:FlavorName:Havengul Mystery
|
||||
ManaCost:no cost
|
||||
Types:Legendary Land
|
||||
T:Mode$ Transformed | ValidCard$ Card.Self | Execute$ TrigReturn | TriggerDescription$ When this land transforms into CARDNAME, return target creature card from your graveyard to the battlefield.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
Name:Holga, Relentless Rager
|
||||
AltName:Jurin, Leading the Charge
|
||||
Variant:UniversesWithin:FlavorName:Jurin, Leading the Charge
|
||||
ManaCost:4 R R
|
||||
Types:Legendary Creature Human Barbarian
|
||||
PT:4/6
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
Name:Ken, Burning Brawler
|
||||
AltName:Aisha of Sparks and Smoke
|
||||
Variant:UniversesWithin:FlavorName:Aisha of Sparks and Smoke
|
||||
ManaCost:1 R R
|
||||
Types:Legendary Creature Human Warrior
|
||||
PT:4/2
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
Name:Lucas, the Sharpshooter
|
||||
AltName:Bjorna, Nightfall Alchemist
|
||||
Variant:UniversesWithin:FlavorName:Bjorna, Nightfall Alchemist
|
||||
ManaCost:U R
|
||||
Types:Legendary Creature Human
|
||||
PT:1/3
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
Name:Lucille
|
||||
AltName:Gisa's Favorite Shovel
|
||||
Variant:UniversesWithin:FlavorName:Gisa's Favorite Shovel
|
||||
ManaCost:1 B
|
||||
Types:Legendary Artifact Equipment
|
||||
S:Mode$ Continuous | Affected$ Creature.EquippedBy | AddPower$ 2 | AddKeyword$ Menace | Description$ Equipped creature gets +2/+0 and has menace.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
Name:Max, the Daredevil
|
||||
AltName:Elmar, Ulvenwald Informant
|
||||
Variant:UniversesWithin:FlavorName:Elmar, Ulvenwald Informant
|
||||
ManaCost:1 R G
|
||||
Types:Legendary Creature Human
|
||||
PT:3/2
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
Name:Michonne, Ruthless Survivor
|
||||
AltName:Enkira, Hostile Scavenger
|
||||
Variant:UniversesWithin:FlavorName:Enkira, Hostile Scavenger
|
||||
ManaCost:3 B G
|
||||
Types:Legendary Creature Human Warrior
|
||||
PT:3/3
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
Name:Mike, the Dungeon Master
|
||||
AltName:Othelm, Sigardian Outcast
|
||||
Variant:UniversesWithin:FlavorName:Othelm, Sigardian Outcast
|
||||
ManaCost:1 G W
|
||||
Types:Legendary Creature Human
|
||||
PT:2/2
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
Name:Mind Flayer, the Shadow
|
||||
AltName:Arvinox, the Mind Flail
|
||||
Variant:UniversesWithin:FlavorName:Arvinox, the Mind Flail
|
||||
ManaCost:4 B B B
|
||||
Types:Legendary Enchantment Creature Horror
|
||||
PT:9/9
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
Name:Negan, the Cold-Blooded
|
||||
AltName:Malik, Grim Manipulator
|
||||
Variant:UniversesWithin:FlavorName:Malik, Grim Manipulator
|
||||
ManaCost:2 R W B
|
||||
Types:Legendary Creature Human Rogue
|
||||
PT:4/3
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
Name:No Secret Is Hidden From Me
|
||||
Name:No Secret Is Hidden from Me
|
||||
ManaCost:no cost
|
||||
Types:Scheme
|
||||
T:Mode$ SetInMotion | ValidCard$ Card.Self | Execute$ TrigDigUntil | TriggerZones$ Command | TriggerDescription$ When you set this scheme in motion, exile cards from the top of your library until you exile a nonland card. You may cast that card without paying its mana cost. Then if you control six or more lands, repeat this process once.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
Name:Rick, Steadfast Leader
|
||||
AltName:Greymond, Avacyn's Stalwart
|
||||
Variant:UniversesWithin:FlavorName:Greymond, Avacyn's Stalwart
|
||||
ManaCost:2 W W
|
||||
Types:Legendary Creature Human Soldier
|
||||
PT:3/4
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
Name:Ryu, World Warrior
|
||||
AltName:Vikya, Scorching Stalwart
|
||||
Variant:UniversesWithin:FlavorName:Vikya, Scorching Stalwart
|
||||
ManaCost:2 W
|
||||
Types:Legendary Creature Human Warrior
|
||||
PT:2/4
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
Name:Simon, Wild Magic Sorcerer
|
||||
AltName:Mathise, Surge Channeler
|
||||
Variant:UniversesWithin:FlavorName:Mathise, Surge Channeler
|
||||
ManaCost:2 U
|
||||
Types:Legendary Creature Human Elf Shaman
|
||||
PT:1/1
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
Name:Will the Wise
|
||||
AltName:Wernog, Rider's Chaplain
|
||||
Variant:UniversesWithin:FlavorName:Wernog, Rider's Chaplain
|
||||
ManaCost:W B
|
||||
Types:Legendary Creature Human
|
||||
PT:1/2
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
Name:Xenk, Paladin Unbroken
|
||||
AltName:Rashel, Fist of Torm
|
||||
Variant:UniversesWithin:FlavorName:Rashel, Fist of Torm
|
||||
ManaCost:2 W W
|
||||
Types:Legendary Creature Human Knight
|
||||
PT:2/4
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
Name:Zangief, the Red Cyclone
|
||||
AltName:Maarika, Brutal Gladiator
|
||||
Variant:UniversesWithin:FlavorName:Maarika, Brutal Gladiator
|
||||
ManaCost:2 B R G
|
||||
Types:Legendary Creature Human Warrior
|
||||
PT:7/4
|
||||
|
||||
@@ -686,7 +686,7 @@ TokensCode=SLD
|
||||
707 R Knight Exemplar @Victor Adame Minguez
|
||||
708 R Fellwar Stone @Dan Frazier
|
||||
709 R Dragon's Hoard @Pedro Potier
|
||||
710 R Command Tower @Joana LaFuente
|
||||
710 R Command Tower @Joana LaFuente ${"flavorName": "Cybertron"}
|
||||
711 R Tireless Tracker @Nils Hamm
|
||||
713 R Swords to Plowshares @Justin Hernandez & Alexis Hernandez
|
||||
714 R Merfolk of the Pearl Trident @Dani Pendergast
|
||||
@@ -1577,7 +1577,7 @@ F1540 M Rainbow Dash @John Thacker
|
||||
1609 R Beastmaster Ascension @Greg Staples
|
||||
1610 R Howl of the Night Pack @Johannes Voss
|
||||
1611 R Second Harvest @Miranda Meeks
|
||||
1612 R Tovolar, Dire Overlord @Zoltan Boros
|
||||
1612 R Tovolar, Dire Overlord @Zoltan Boros ${"flavorName": "NOT A WOLF // KING OF WOLVES"}
|
||||
1614 R Brash Taunter @Mark Behm & Scott Okumura
|
||||
1615 R Goblin Chieftain @Jakub Kasper & Scott Okumura
|
||||
1616 R Goblin Ringleader @Svetlin Velinov & Scott Okumura
|
||||
@@ -1902,7 +1902,7 @@ F1540 M Rainbow Dash @John Thacker
|
||||
1929 M Toxrill, the Corrosive @Gregg Schigiel
|
||||
1930 M Toski, Bearer of Secrets @Caleb Meurer
|
||||
1931 R Barktooth Warbeard @Caleb Meurer
|
||||
1932 M Jodah, the Unifier @Caleb Meurer
|
||||
1932 M Jodah, the Unifier @Caleb Meurer ${"flavorName": "SpongeBob SquarePants"}
|
||||
1933 R Counterspell @Tyler Walpole
|
||||
1934 R Daze @Tyler Walpole
|
||||
1935 R Inevitable Betrayal @Tyler Walpole
|
||||
@@ -2113,7 +2113,7 @@ F1540 M Rainbow Dash @John Thacker
|
||||
2176 R Descent into Avernus @Stephen Andrade
|
||||
2177 R Reckless Endeavor @Stephen Andrade
|
||||
2178 M Sneak Attack @Stephen Andrade
|
||||
2179 R Abrade @Stephen Andrade
|
||||
2179 R Abrade @Stephen Andrade ${"flavorName": "You're Gonna Need a Bigger Boat"}
|
||||
2181 M Bruvac the Grandiloquent @Akirant
|
||||
2182 R Windfall @Dan Mumford
|
||||
2183 M Captain N'ghathrod @Akirant
|
||||
@@ -2212,7 +2212,7 @@ F1540 M Rainbow Dash @John Thacker
|
||||
7027 R Tibalt's Trickery @Babs Webb
|
||||
7028 R Minds Aglow @Evan Geltosky
|
||||
7029 R Command Tower @Dan Black
|
||||
7030 R Command Tower @Sylvain Sarrailh
|
||||
7030 R Command Tower @Sylvain Sarrailh ${"flavorName": "Master Emerald Shrine"}
|
||||
7031 M Lotus Petal @Mike Burns
|
||||
7032 M Lotus Petal @Mike Burns
|
||||
7033 M Lotus Petal @Mike Burns
|
||||
|
||||
@@ -4185,7 +4185,7 @@ SHM-258 C Pili-Pala @Ron Spencer
|
||||
SHM-260 R Reaper King @Jim Murray
|
||||
SHM-263 C Scuttlemutt @Jeremy Jarvis
|
||||
SHM-267 U Umbral Mantle @Richard Sardinha
|
||||
SLX-4 R Elmar, Ulvenwald Informant @Eliz Roxs
|
||||
SLX-4 R Elmar, Ulvenwald Informant @Eliz Roxs ${"variant": "UniversesWithin"}
|
||||
SNC-14 R Giada, Font of Hope @Eric Deschamps
|
||||
SNC-15 M Halo Fountain @Anastasia Ovchinnikova
|
||||
SNC-18 C Inspiring Overseer @Irina Nordsol
|
||||
|
||||
@@ -102,54 +102,54 @@ F192 R Souvenir T-Shirt @Michael Phillippi
|
||||
F197 U The Big Top @Kirsten Zirngibl
|
||||
F198 C Nearby Planet @Bruce Brenneise
|
||||
F199 R Urza's Fun House @Dmitry Burmak
|
||||
F203a R Centrifuge @Greg Staples $A
|
||||
F203b R Centrifuge @Greg Staples $B
|
||||
F207a C Cover the Spot @Jeff Miracola $A
|
||||
F207b C Cover the Spot @Jeff Miracola $B
|
||||
F207c C Cover the Spot @Jeff Miracola $C
|
||||
F207d C Cover the Spot @Jeff Miracola $D
|
||||
F208a C Dart Throw @Gaboleps $A
|
||||
F208b C Dart Throw @Gaboleps $B
|
||||
F208c C Dart Throw @Gaboleps $C
|
||||
F208d C Dart Throw @Gaboleps $D
|
||||
F213a R Gallery of Legends @Jakub Kasper $A
|
||||
F213b R Gallery of Legends @Jakub Kasper $B
|
||||
F214a R Gift Shop @Matt Gaser $A
|
||||
F214b R Gift Shop @Matt Gaser $B
|
||||
F215a U Guess Your Fate @Bruce Brenneise $A
|
||||
F215b U Guess Your Fate @Bruce Brenneise $B
|
||||
F215c U Guess Your Fate @Bruce Brenneise $C
|
||||
F215d U Guess Your Fate @Bruce Brenneise $D
|
||||
F220a R Log Flume @Marco Bucci $A
|
||||
F220b R Log Flume @Marco Bucci $B
|
||||
F221a R Memory Test @Setor Fiadzigbey $A
|
||||
F221b R Memory Test @Setor Fiadzigbey $B
|
||||
F224a R Push Your Luck @Sebastian Giacobino $A
|
||||
F224b R Push Your Luck @Sebastian Giacobino $B
|
||||
F226a U Scavenger Hunt @Jamroz Gary $A
|
||||
F226b U Scavenger Hunt @Jamroz Gary $B
|
||||
F226c U Scavenger Hunt @Jamroz Gary $C
|
||||
F226d U Scavenger Hunt @Jamroz Gary $D
|
||||
F226e U Scavenger Hunt @Jamroz Gary $E
|
||||
F226f U Scavenger Hunt @Jamroz Gary $F
|
||||
F228a U Squirrel Stack @Andrea Radeck $A
|
||||
F228b U Squirrel Stack @Andrea Radeck $B
|
||||
F228c U Squirrel Stack @Andrea Radeck $C
|
||||
F228d U Squirrel Stack @Andrea Radeck $D
|
||||
F228e U Squirrel Stack @Andrea Radeck $E
|
||||
F228f U Squirrel Stack @Andrea Radeck $F
|
||||
F230a U The Superlatorium @Simon Dominic $A
|
||||
F230b U The Superlatorium @Simon Dominic $B
|
||||
F230c U The Superlatorium @Simon Dominic $C
|
||||
F230d U The Superlatorium @Simon Dominic $D
|
||||
F230e U The Superlatorium @Simon Dominic $E
|
||||
F230f U The Superlatorium @Simon Dominic $F
|
||||
F233a U Trivia Contest @Caroline Gariba $A
|
||||
F233b U Trivia Contest @Caroline Gariba $B
|
||||
F233c U Trivia Contest @Caroline Gariba $C
|
||||
F233d U Trivia Contest @Caroline Gariba $D
|
||||
F233e U Trivia Contest @Caroline Gariba $E
|
||||
F233f U Trivia Contest @Caroline Gariba $F
|
||||
F203a R Centrifuge @Greg Staples ${"variant": "A"}
|
||||
F203b R Centrifuge @Greg Staples ${"variant": "B"}
|
||||
F207a C Cover the Spot @Jeff Miracola ${"variant": "A"}
|
||||
F207b C Cover the Spot @Jeff Miracola ${"variant": "B"}
|
||||
F207c C Cover the Spot @Jeff Miracola ${"variant": "C"}
|
||||
F207d C Cover the Spot @Jeff Miracola ${"variant": "D"}
|
||||
F208a C Dart Throw @Gaboleps ${"variant": "A"}
|
||||
F208b C Dart Throw @Gaboleps ${"variant": "B"}
|
||||
F208c C Dart Throw @Gaboleps ${"variant": "C"}
|
||||
F208d C Dart Throw @Gaboleps ${"variant": "D"}
|
||||
F213a R Gallery of Legends @Jakub Kasper ${"variant": "A"}
|
||||
F213b R Gallery of Legends @Jakub Kasper ${"variant": "B"}
|
||||
F214a R Gift Shop @Matt Gaser ${"variant": "A"}
|
||||
F214b R Gift Shop @Matt Gaser ${"variant": "B"}
|
||||
F215a U Guess Your Fate @Bruce Brenneise ${"variant": "A"}
|
||||
F215b U Guess Your Fate @Bruce Brenneise ${"variant": "B"}
|
||||
F215c U Guess Your Fate @Bruce Brenneise ${"variant": "C"}
|
||||
F215d U Guess Your Fate @Bruce Brenneise ${"variant": "D"}
|
||||
F220a R Log Flume @Marco Bucci ${"variant": "A"}
|
||||
F220b R Log Flume @Marco Bucci ${"variant": "B"}
|
||||
F221a R Memory Test @Setor Fiadzigbey ${"variant": "A"}
|
||||
F221b R Memory Test @Setor Fiadzigbey ${"variant": "B"}
|
||||
F224a R Push Your Luck @Sebastian Giacobino ${"variant": "A"}
|
||||
F224b R Push Your Luck @Sebastian Giacobino ${"variant": "B"}
|
||||
F226a U Scavenger Hunt @Jamroz Gary ${"variant": "A"}
|
||||
F226b U Scavenger Hunt @Jamroz Gary ${"variant": "B"}
|
||||
F226c U Scavenger Hunt @Jamroz Gary ${"variant": "C"}
|
||||
F226d U Scavenger Hunt @Jamroz Gary ${"variant": "D"}
|
||||
F226e U Scavenger Hunt @Jamroz Gary ${"variant": "E"}
|
||||
F226f U Scavenger Hunt @Jamroz Gary ${"variant": "F"}
|
||||
F228a U Squirrel Stack @Andrea Radeck ${"variant": "A"}
|
||||
F228b U Squirrel Stack @Andrea Radeck ${"variant": "B"}
|
||||
F228c U Squirrel Stack @Andrea Radeck ${"variant": "C"}
|
||||
F228d U Squirrel Stack @Andrea Radeck ${"variant": "D"}
|
||||
F228e U Squirrel Stack @Andrea Radeck ${"variant": "E"}
|
||||
F228f U Squirrel Stack @Andrea Radeck ${"variant": "F"}
|
||||
F230a U The Superlatorium @Simon Dominic ${"variant": "A"}
|
||||
F230b U The Superlatorium @Simon Dominic ${"variant": "B"}
|
||||
F230c U The Superlatorium @Simon Dominic ${"variant": "C"}
|
||||
F230d U The Superlatorium @Simon Dominic ${"variant": "D"}
|
||||
F230e U The Superlatorium @Simon Dominic ${"variant": "E"}
|
||||
F230f U The Superlatorium @Simon Dominic ${"variant": "F"}
|
||||
F233a U Trivia Contest @Caroline Gariba ${"variant": "A"}
|
||||
F233b U Trivia Contest @Caroline Gariba ${"variant": "B"}
|
||||
F233c U Trivia Contest @Caroline Gariba ${"variant": "C"}
|
||||
F233d U Trivia Contest @Caroline Gariba ${"variant": "D"}
|
||||
F233e U Trivia Contest @Caroline Gariba ${"variant": "E"}
|
||||
F233f U Trivia Contest @Caroline Gariba ${"variant": "F"}
|
||||
F245 R Katerina of Myra's Marvels @David Semple
|
||||
F246 R Solaflora, Intergalactic Icon @Scooter
|
||||
F247 R Fluros of Myra's Marvels @David Semple
|
||||
@@ -391,93 +391,93 @@ F538 R Water Gun Balloon Game @Ralph Horsley
|
||||
194 C Ticket Turbotubes @Matt Gaser
|
||||
195 C Ticketomaton @Michael Phillippi
|
||||
196 U Wicker Picker @Igor Grechanyi
|
||||
200a U Balloon Stand @Jakub Kasper $A
|
||||
200b U Balloon Stand @Jakub Kasper $B
|
||||
200c U Balloon Stand @Jakub Kasper $C
|
||||
200d U Balloon Stand @Jakub Kasper $D
|
||||
201a U Bounce Chamber @Dmitry Burmak $A
|
||||
201b U Bounce Chamber @Dmitry Burmak $B
|
||||
201c U Bounce Chamber @Dmitry Burmak $C
|
||||
201d U Bounce Chamber @Dmitry Burmak $D
|
||||
202a U Bumper Cars @Gabor Szikszai $A
|
||||
202b U Bumper Cars @Gabor Szikszai $B
|
||||
202c U Bumper Cars @Gabor Szikszai $C
|
||||
202d U Bumper Cars @Gabor Szikszai $D
|
||||
202e U Bumper Cars @Gabor Szikszai $E
|
||||
202f U Bumper Cars @Gabor Szikszai $F
|
||||
204a C Clown Extruder @Marco Bucci $A
|
||||
204b C Clown Extruder @Marco Bucci $B
|
||||
204c C Clown Extruder @Marco Bucci $C
|
||||
204d C Clown Extruder @Marco Bucci $D
|
||||
205a U Concession Stand @David Sladek $A
|
||||
205b U Concession Stand @David Sladek $B
|
||||
205c U Concession Stand @David Sladek $C
|
||||
205d U Concession Stand @David Sladek $D
|
||||
206a C Costume Shop @Raluca Marinescu $A
|
||||
206b C Costume Shop @Raluca Marinescu $B
|
||||
206c C Costume Shop @Raluca Marinescu $C
|
||||
206d C Costume Shop @Raluca Marinescu $D
|
||||
206e C Costume Shop @Raluca Marinescu $E
|
||||
206f C Costume Shop @Raluca Marinescu $F
|
||||
209a C Drop Tower @Dmitry Burmak $A
|
||||
209b C Drop Tower @Dmitry Burmak $B
|
||||
209c C Drop Tower @Dmitry Burmak $C
|
||||
209d C Drop Tower @Dmitry Burmak $D
|
||||
209e C Drop Tower @Dmitry Burmak $E
|
||||
209f C Drop Tower @Dmitry Burmak $F
|
||||
200a U Balloon Stand @Jakub Kasper ${"variant": "A"}
|
||||
200b U Balloon Stand @Jakub Kasper ${"variant": "B"}
|
||||
200c U Balloon Stand @Jakub Kasper ${"variant": "C"}
|
||||
200d U Balloon Stand @Jakub Kasper ${"variant": "D"}
|
||||
201a U Bounce Chamber @Dmitry Burmak ${"variant": "A"}
|
||||
201b U Bounce Chamber @Dmitry Burmak ${"variant": "B"}
|
||||
201c U Bounce Chamber @Dmitry Burmak ${"variant": "C"}
|
||||
201d U Bounce Chamber @Dmitry Burmak ${"variant": "D"}
|
||||
202a U Bumper Cars @Gabor Szikszai ${"variant": "A"}
|
||||
202b U Bumper Cars @Gabor Szikszai ${"variant": "B"}
|
||||
202c U Bumper Cars @Gabor Szikszai ${"variant": "C"}
|
||||
202d U Bumper Cars @Gabor Szikszai ${"variant": "D"}
|
||||
202e U Bumper Cars @Gabor Szikszai ${"variant": "E"}
|
||||
202f U Bumper Cars @Gabor Szikszai ${"variant": "F"}
|
||||
204a C Clown Extruder @Marco Bucci ${"variant": "A"}
|
||||
204b C Clown Extruder @Marco Bucci ${"variant": "B"}
|
||||
204c C Clown Extruder @Marco Bucci ${"variant": "C"}
|
||||
204d C Clown Extruder @Marco Bucci ${"variant": "D"}
|
||||
205a U Concession Stand @David Sladek ${"variant": "A"}
|
||||
205b U Concession Stand @David Sladek ${"variant": "B"}
|
||||
205c U Concession Stand @David Sladek ${"variant": "C"}
|
||||
205d U Concession Stand @David Sladek ${"variant": "D"}
|
||||
206a C Costume Shop @Raluca Marinescu ${"variant": "A"}
|
||||
206b C Costume Shop @Raluca Marinescu ${"variant": "B"}
|
||||
206c C Costume Shop @Raluca Marinescu ${"variant": "C"}
|
||||
206d C Costume Shop @Raluca Marinescu ${"variant": "D"}
|
||||
206e C Costume Shop @Raluca Marinescu ${"variant": "E"}
|
||||
206f C Costume Shop @Raluca Marinescu ${"variant": "F"}
|
||||
209a C Drop Tower @Dmitry Burmak ${"variant": "A"}
|
||||
209b C Drop Tower @Dmitry Burmak ${"variant": "B"}
|
||||
209c C Drop Tower @Dmitry Burmak ${"variant": "C"}
|
||||
209d C Drop Tower @Dmitry Burmak ${"variant": "D"}
|
||||
209e C Drop Tower @Dmitry Burmak ${"variant": "E"}
|
||||
209f C Drop Tower @Dmitry Burmak ${"variant": "F"}
|
||||
210 R Ferris Wheel @Kirsten Zirngibl
|
||||
211a C Foam Weapons Kiosk @Matt Gaser $A
|
||||
211b C Foam Weapons Kiosk @Matt Gaser $B
|
||||
211c C Foam Weapons Kiosk @Matt Gaser $C
|
||||
211d C Foam Weapons Kiosk @Matt Gaser $D
|
||||
212a C Fortune Teller @Jamroz Gary $A
|
||||
212b C Fortune Teller @Jamroz Gary $B
|
||||
212c C Fortune Teller @Jamroz Gary $C
|
||||
212d C Fortune Teller @Jamroz Gary $D
|
||||
212e C Fortune Teller @Jamroz Gary $E
|
||||
212f C Fortune Teller @Jamroz Gary $F
|
||||
216a R Hall of Mirrors @Vincent Christiaens $A
|
||||
216b R Hall of Mirrors @Vincent Christiaens $B
|
||||
217a R Haunted House @Dmitry Burmak $A
|
||||
217b R Haunted House @Dmitry Burmak $B
|
||||
218a U Information Booth @Gaboleps $A
|
||||
218b U Information Booth @Gaboleps $B
|
||||
218c U Information Booth @Gaboleps $C
|
||||
218d U Information Booth @Gaboleps $D
|
||||
219a C Kiddie Coaster @Marco Bucci $A
|
||||
219b C Kiddie Coaster @Marco Bucci $B
|
||||
219c C Kiddie Coaster @Marco Bucci $C
|
||||
219d C Kiddie Coaster @Marco Bucci $D
|
||||
219e C Kiddie Coaster @Marco Bucci $E
|
||||
219f C Kiddie Coaster @Marco Bucci $F
|
||||
222a R Merry-Go-Round @Carl Critchlow $A
|
||||
222b R Merry-Go-Round @Carl Critchlow $B
|
||||
223a C Pick-a-Beeble @Dave Greco $A
|
||||
223b C Pick-a-Beeble @Dave Greco $B
|
||||
223c C Pick-a-Beeble @Dave Greco $C
|
||||
223d C Pick-a-Beeble @Dave Greco $D
|
||||
223e C Pick-a-Beeble @Dave Greco $E
|
||||
223f C Pick-a-Beeble @Dave Greco $F
|
||||
225a U Roller Coaster @Gabor Szikszai $A
|
||||
225b U Roller Coaster @Gabor Szikszai $B
|
||||
225c U Roller Coaster @Gabor Szikszai $C
|
||||
225d U Roller Coaster @Gabor Szikszai $D
|
||||
227a C Spinny Ride @Aaron J. Riley $A
|
||||
227b C Spinny Ride @Aaron J. Riley $B
|
||||
227c C Spinny Ride @Aaron J. Riley $C
|
||||
227d C Spinny Ride @Aaron J. Riley $D
|
||||
227e C Spinny Ride @Aaron J. Riley $E
|
||||
227f C Spinny Ride @Aaron J. Riley $F
|
||||
229a R Storybook Ride @Dmitry Burmak $A
|
||||
229b R Storybook Ride @Dmitry Burmak $B
|
||||
231a R Swinging Ship @Mike Burns $A
|
||||
231b R Swinging Ship @Mike Burns $B
|
||||
232a U Trash Bin @Greg Bobrowski $A
|
||||
232b U Trash Bin @Greg Bobrowski $B
|
||||
232c U Trash Bin @Greg Bobrowski $C
|
||||
232d U Trash Bin @Greg Bobrowski $D
|
||||
234a R Tunnel of Love @Vladimir Krisetskiy $A
|
||||
234b R Tunnel of Love @Vladimir Krisetskiy $B
|
||||
211a C Foam Weapons Kiosk @Matt Gaser ${"variant": "A"}
|
||||
211b C Foam Weapons Kiosk @Matt Gaser ${"variant": "B"}
|
||||
211c C Foam Weapons Kiosk @Matt Gaser ${"variant": "C"}
|
||||
211d C Foam Weapons Kiosk @Matt Gaser ${"variant": "D"}
|
||||
212a C Fortune Teller @Jamroz Gary ${"variant": "A"}
|
||||
212b C Fortune Teller @Jamroz Gary ${"variant": "B"}
|
||||
212c C Fortune Teller @Jamroz Gary ${"variant": "C"}
|
||||
212d C Fortune Teller @Jamroz Gary ${"variant": "D"}
|
||||
212e C Fortune Teller @Jamroz Gary ${"variant": "E"}
|
||||
212f C Fortune Teller @Jamroz Gary ${"variant": "F"}
|
||||
216a R Hall of Mirrors @Vincent Christiaens ${"variant": "A"}
|
||||
216b R Hall of Mirrors @Vincent Christiaens ${"variant": "B"}
|
||||
217a R Haunted House @Dmitry Burmak ${"variant": "A"}
|
||||
217b R Haunted House @Dmitry Burmak ${"variant": "B"}
|
||||
218a U Information Booth @Gaboleps ${"variant": "A"}
|
||||
218b U Information Booth @Gaboleps ${"variant": "B"}
|
||||
218c U Information Booth @Gaboleps ${"variant": "C"}
|
||||
218d U Information Booth @Gaboleps ${"variant": "D"}
|
||||
219a C Kiddie Coaster @Marco Bucci ${"variant": "A"}
|
||||
219b C Kiddie Coaster @Marco Bucci ${"variant": "B"}
|
||||
219c C Kiddie Coaster @Marco Bucci ${"variant": "C"}
|
||||
219d C Kiddie Coaster @Marco Bucci ${"variant": "D"}
|
||||
219e C Kiddie Coaster @Marco Bucci ${"variant": "E"}
|
||||
219f C Kiddie Coaster @Marco Bucci ${"variant": "F"}
|
||||
222a R Merry-Go-Round @Carl Critchlow ${"variant": "A"}
|
||||
222b R Merry-Go-Round @Carl Critchlow ${"variant": "B"}
|
||||
223a C Pick-a-Beeble @Dave Greco ${"variant": "A"}
|
||||
223b C Pick-a-Beeble @Dave Greco ${"variant": "B"}
|
||||
223c C Pick-a-Beeble @Dave Greco ${"variant": "C"}
|
||||
223d C Pick-a-Beeble @Dave Greco ${"variant": "D"}
|
||||
223e C Pick-a-Beeble @Dave Greco ${"variant": "E"}
|
||||
223f C Pick-a-Beeble @Dave Greco ${"variant": "F"}
|
||||
225a U Roller Coaster @Gabor Szikszai ${"variant": "A"}
|
||||
225b U Roller Coaster @Gabor Szikszai ${"variant": "B"}
|
||||
225c U Roller Coaster @Gabor Szikszai ${"variant": "C"}
|
||||
225d U Roller Coaster @Gabor Szikszai ${"variant": "D"}
|
||||
227a C Spinny Ride @Aaron J. Riley ${"variant": "A"}
|
||||
227b C Spinny Ride @Aaron J. Riley ${"variant": "B"}
|
||||
227c C Spinny Ride @Aaron J. Riley ${"variant": "C"}
|
||||
227d C Spinny Ride @Aaron J. Riley ${"variant": "D"}
|
||||
227e C Spinny Ride @Aaron J. Riley ${"variant": "E"}
|
||||
227f C Spinny Ride @Aaron J. Riley ${"variant": "F"}
|
||||
229a R Storybook Ride @Dmitry Burmak ${"variant": "A"}
|
||||
229b R Storybook Ride @Dmitry Burmak ${"variant": "B"}
|
||||
231a R Swinging Ship @Mike Burns ${"variant": "A"}
|
||||
231b R Swinging Ship @Mike Burns ${"variant": "B"}
|
||||
232a U Trash Bin @Greg Bobrowski ${"variant": "A"}
|
||||
232b U Trash Bin @Greg Bobrowski ${"variant": "B"}
|
||||
232c U Trash Bin @Greg Bobrowski ${"variant": "C"}
|
||||
232d U Trash Bin @Greg Bobrowski ${"variant": "D"}
|
||||
234a R Tunnel of Love @Vladimir Krisetskiy ${"variant": "A"}
|
||||
234b R Tunnel of Love @Vladimir Krisetskiy ${"variant": "B"}
|
||||
235 L Plains @Adam Paquette
|
||||
236 L Island @Adam Paquette
|
||||
237 L Swamp @Adam Paquette
|
||||
|
||||
@@ -21,12 +21,12 @@ ScryfallCode=UST
|
||||
9 U Half-Kitten, Half- @Andrea Radeck
|
||||
10 C Humming- @Mark Behm
|
||||
11 R Jackknight @Ben Wootten
|
||||
12a U Knight of the Kitchen Sink @Mark A. Nelson $A
|
||||
12b U Knight of the Kitchen Sink @Mark A. Nelson $B
|
||||
12c U Knight of the Kitchen Sink @Mark A. Nelson $C
|
||||
12d U Knight of the Kitchen Sink @Mark A. Nelson $D
|
||||
12e U Knight of the Kitchen Sink @Mark A. Nelson $E
|
||||
12f U Knight of the Kitchen Sink @Mark A. Nelson $F
|
||||
12a U Knight of the Kitchen Sink @Mark A. Nelson ${"variant": "A"}
|
||||
12b U Knight of the Kitchen Sink @Mark A. Nelson ${"variant": "B"}
|
||||
12c U Knight of the Kitchen Sink @Mark A. Nelson ${"variant": "C"}
|
||||
12d U Knight of the Kitchen Sink @Mark A. Nelson ${"variant": "D"}
|
||||
12e U Knight of the Kitchen Sink @Mark A. Nelson ${"variant": "E"}
|
||||
12f U Knight of the Kitchen Sink @Mark A. Nelson ${"variant": "F"}
|
||||
13 U Knight of the Widget @Emrah Elmasli
|
||||
14 U Midlife Upgrade @Hector Ortiz
|
||||
15 R Oddly Uneven @Ben Wootten
|
||||
@@ -66,12 +66,12 @@ ScryfallCode=UST
|
||||
46 U Spy Eye @Ben Wootten
|
||||
47 U Suspicious Nanny @Chris Seaman
|
||||
48 C Time Out @Dave Allsop
|
||||
49a R Very Cryptic Command @Wayne England $A
|
||||
49b R Very Cryptic Command @Zoltan Boros $B
|
||||
49c R Very Cryptic Command @Zoltan Boros $C
|
||||
49d R Very Cryptic Command @Zoltan Boros $D
|
||||
49e R Very Cryptic Command @Zoltan Boros $E
|
||||
49f R Very Cryptic Command @Zoltan Boros $F
|
||||
49a R Very Cryptic Command @Wayne England ${"variant": "A"}
|
||||
49b R Very Cryptic Command @Zoltan Boros ${"variant": "B"}
|
||||
49c R Very Cryptic Command @Zoltan Boros ${"variant": "C"}
|
||||
49d R Very Cryptic Command @Zoltan Boros ${"variant": "D"}
|
||||
49e R Very Cryptic Command @Zoltan Boros ${"variant": "E"}
|
||||
49f R Very Cryptic Command @Zoltan Boros ${"variant": "F"}
|
||||
50 C Wall of Fortune @Tom Babbey
|
||||
51 C Big Boa Constrictor @Kari Christensen
|
||||
52 C capital offense @Matt Dixon
|
||||
@@ -92,12 +92,12 @@ ScryfallCode=UST
|
||||
64 U Overt Operative @Bram Sels
|
||||
65 U "Rumors of My Death..." @Alex Konstad
|
||||
66 U Skull Saucer @Mike Burns
|
||||
67a U Sly Spy @Michael Phillippi $A
|
||||
67b U Sly Spy @Michael Phillippi $B
|
||||
67c U Sly Spy @Michael Phillippi $C
|
||||
67d U Sly Spy @Michael Phillippi $D
|
||||
67e U Sly Spy @Michael Phillippi $E
|
||||
67f U Sly Spy @Michael Phillippi $F
|
||||
67a U Sly Spy @Michael Phillippi ${"variant": "A"}
|
||||
67b U Sly Spy @Michael Phillippi ${"variant": "B"}
|
||||
67c U Sly Spy @Michael Phillippi ${"variant": "C"}
|
||||
67d U Sly Spy @Michael Phillippi ${"variant": "D"}
|
||||
67e U Sly Spy @Michael Phillippi ${"variant": "E"}
|
||||
67f U Sly Spy @Michael Phillippi ${"variant": "F"}
|
||||
68 C Snickering Squirrel @Michael Phillippi
|
||||
69 R Spike, Tournament Grinder @Zoltan Boros
|
||||
70 U Squirrel-Powered Scheme @Even Amundsen
|
||||
@@ -112,12 +112,12 @@ ScryfallCode=UST
|
||||
79 C Common Iguana @Brynn Metheney
|
||||
80 R The Countdown Is at One @Jesper Ejsing
|
||||
81 C Feisty Stegosaurus @Kari Christensen
|
||||
82a U Garbage Elemental @Hector Ortiz $A
|
||||
82b U Garbage Elemental @Hector Ortiz $B
|
||||
82c U Garbage Elemental @Hector Ortiz $C
|
||||
82d U Garbage Elemental @Hector Ortiz $D
|
||||
82e U Garbage Elemental @Hector Ortiz $E
|
||||
82f U Garbage Elemental @Hector Ortiz $F
|
||||
82a U Garbage Elemental @Hector Ortiz ${"variant": "A"}
|
||||
82b U Garbage Elemental @Hector Ortiz ${"variant": "B"}
|
||||
82c U Garbage Elemental @Hector Ortiz ${"variant": "C"}
|
||||
82d U Garbage Elemental @Hector Ortiz ${"variant": "D"}
|
||||
82e U Garbage Elemental @Hector Ortiz ${"variant": "E"}
|
||||
82f U Garbage Elemental @Hector Ortiz ${"variant": "F"}
|
||||
83 U Goblin Haberdasher @Jesper Ejsing
|
||||
84 U Half-Orc, Half- @Kev Walker
|
||||
85 C Hammer Helper @Dave Allsop
|
||||
@@ -153,12 +153,12 @@ ScryfallCode=UST
|
||||
110 C Ground Pounder @Warren Mahy
|
||||
111 U Half-Squirrel, Half- @Andrea Radeck
|
||||
112 R Hydradoodle @Mathias Kollros
|
||||
113a R Ineffable Blessing @Milivoj Ćeran $A
|
||||
113b R Ineffable Blessing @Milivoj Ćeran $B
|
||||
113c R Ineffable Blessing @Milivoj Ćeran $C
|
||||
113d R Ineffable Blessing @Milivoj Ćeran $D
|
||||
113e R Ineffable Blessing @Milivoj Ćeran $E
|
||||
113f R Ineffable Blessing @Milivoj Ćeran $F
|
||||
113a R Ineffable Blessing @Milivoj Ćeran ${"variant": "A"}
|
||||
113b R Ineffable Blessing @Milivoj Ćeran ${"variant": "B"}
|
||||
113c R Ineffable Blessing @Milivoj Ćeran ${"variant": "C"}
|
||||
113d R Ineffable Blessing @Milivoj Ćeran ${"variant": "D"}
|
||||
113e R Ineffable Blessing @Milivoj Ćeran ${"variant": "E"}
|
||||
113f R Ineffable Blessing @Milivoj Ćeran ${"variant": "F"}
|
||||
114 C Joyride Rigger @Wayne Reynolds
|
||||
115 U Monkey- @Andrea Radeck
|
||||
116 C Mother Kangaroo @Andrea Radeck
|
||||
@@ -195,12 +195,12 @@ ScryfallCode=UST
|
||||
145c C Despondent Killbot @Alex Konstad
|
||||
145d C Enraged Killbot @Alex Konstad
|
||||
146 U Entirely Normal Armchair @Tom Babbey
|
||||
147a R Everythingamajig @Chris Seaman $A
|
||||
147b R Everythingamajig @Chris Seaman $B
|
||||
147c R Everythingamajig @Chris Seaman $C
|
||||
147d R Everythingamajig @Chris Seaman $D
|
||||
147e R Everythingamajig @Chris Seaman $E
|
||||
147f R Everythingamajig @Chris Seaman $F
|
||||
147a R Everythingamajig @Chris Seaman ${"variant": "A"}
|
||||
147b R Everythingamajig @Chris Seaman ${"variant": "B"}
|
||||
147c R Everythingamajig @Chris Seaman ${"variant": "C"}
|
||||
147d R Everythingamajig @Chris Seaman ${"variant": "D"}
|
||||
147e R Everythingamajig @Chris Seaman ${"variant": "E"}
|
||||
147f R Everythingamajig @Chris Seaman ${"variant": "F"}
|
||||
148 C Gnome-Made Engine @Sean Murray
|
||||
149 R Handy Dandy Clone Machine @Mike Burns
|
||||
150 R Kindslaver @Zoltan Boros
|
||||
|
||||
@@ -152,7 +152,7 @@ public class LimitedPlayer {
|
||||
removedFromPool = true;
|
||||
removedFromCardPool.add(bestPick);
|
||||
if (choice.equals("Animus of Predation")) {
|
||||
addLog(name() + " removed " + bestPick.getName() + " from the draft with " + choice + ".");
|
||||
addLog(name() + " removed " + bestPick.getDisplayName() + " from the draft with " + choice + ".");
|
||||
} else if (choice.equals("Cogwork Grinder")) {
|
||||
addLog(name() + " removed a card face down from the draft with " + choice + ".");
|
||||
}
|
||||
@@ -169,14 +169,14 @@ public class LimitedPlayer {
|
||||
// But just log that a reveal "happened"
|
||||
addLog(this.name() + " revealed a card to " + fromPlayer.name() + " via Cogwork Spy.");
|
||||
} else {
|
||||
addLog(this.name() + " revealed " + bestPick.getName() + " to you with Cogwork Spy.");
|
||||
addLog(this.name() + " revealed " + bestPick.getDisplayName() + " to you with Cogwork Spy.");
|
||||
}
|
||||
|
||||
fromPlayer.playerFlags &= ~SpyNextCardDrafted;
|
||||
}
|
||||
|
||||
if ((playerFlags & SearcherNoteNext) == SearcherNoteNext) {
|
||||
addLog(name() + " revealed " + bestPick.getName() + " for Aether Searcher.");
|
||||
addLog(name() + " revealed " + bestPick.getDisplayName() + " for Aether Searcher.");
|
||||
playerFlags &= ~SearcherNoteNext;
|
||||
List<String> note = noted.computeIfAbsent("Aether Searcher", k -> Lists.newArrayList());
|
||||
note.add(String.valueOf(bestPick.getName()));
|
||||
@@ -184,7 +184,7 @@ public class LimitedPlayer {
|
||||
|
||||
if ((playerFlags & SmugglerCaptainActive) == SmugglerCaptainActive) {
|
||||
if (revealWithSmuggler(bestPick)) {
|
||||
addLog(name() + " revealed " + bestPick.getName() + " for Smuggler Captain.");
|
||||
addLog(name() + " revealed " + bestPick.getDisplayName() + " for Smuggler Captain.");
|
||||
playerFlags &= ~SmugglerCaptainActive;
|
||||
List<String> note = noted.computeIfAbsent("Smuggler Captain", k -> Lists.newArrayList());
|
||||
note.add(String.valueOf(bestPick.getName()));
|
||||
@@ -297,7 +297,7 @@ public class LimitedPlayer {
|
||||
List<String> note = noted.computeIfAbsent(bestPick.getName(), k -> Lists.newArrayList());
|
||||
note.add(String.valueOf(draftedThisRound));
|
||||
|
||||
addLog(name() + " revealed " + bestPick.getName() + " and noted " + draftedThisRound + " cards drafted this round.");
|
||||
addLog(name() + " revealed " + bestPick.getDisplayName() + " and noted " + draftedThisRound + " cards drafted this round.");
|
||||
} else if (Iterables.contains(draftActions, "As you draft CARDNAME, the player to your right chooses a color, you choose another color, then the player to your left chooses a third color.")) {
|
||||
List<String> chosenColors = new ArrayList<>();
|
||||
|
||||
@@ -320,7 +320,7 @@ public class LimitedPlayer {
|
||||
List<String> note = noted.computeIfAbsent(bestPick.getName(), k -> Lists.newArrayList());
|
||||
note.add(String.join(",", chosenColors));
|
||||
|
||||
addLog(name() + " revealed " + bestPick.getName() + " and noted " + String.join(",", chosenColors) + " chosen colors.");
|
||||
addLog(name() + " revealed " + bestPick.getDisplayName() + " and noted " + String.join(",", chosenColors) + " chosen colors.");
|
||||
}
|
||||
else {
|
||||
if (Iterables.contains(draftActions, "You may look at the next card drafted from this booster pack.")) {
|
||||
@@ -328,7 +328,7 @@ public class LimitedPlayer {
|
||||
} else if (fromPlayer != null && Iterables.contains(draftActions, "Note the player who passed CARDNAME to you.")) {
|
||||
List<String> note = noted.computeIfAbsent(bestPick.getName(), k -> Lists.newArrayList());
|
||||
note.add(String.valueOf(fromPlayer.order));
|
||||
addLog(name() + " revealed " + bestPick.getName() + " and noted " + fromPlayer.name() + " passed it.");
|
||||
addLog(name() + " revealed " + bestPick.getDisplayName() + " and noted " + fromPlayer.name() + " passed it.");
|
||||
} else if (Iterables.contains(draftActions, "Reveal the next card you draft and note its name.")) {
|
||||
playerFlags |= SearcherNoteNext;
|
||||
} else if (Iterables.contains(draftActions, "The next time a player drafts a card from this booster pack, guess that card's name. Then that player reveals the drafted card.")) {
|
||||
@@ -337,12 +337,12 @@ public class LimitedPlayer {
|
||||
addSingleBoosterPack();
|
||||
}
|
||||
|
||||
addLog(name() + " revealed " + bestPick.getName() + " as " + name() + " drafted it.");
|
||||
addLog(name() + " revealed " + bestPick.getDisplayName() + " as " + name() + " drafted it.");
|
||||
}
|
||||
}
|
||||
if (Iterables.contains(draftActions, "Draft CARDNAME face up.")) {
|
||||
faceUp.add(bestPick);
|
||||
addLog(name() + " drafted " + bestPick.getName() + " face up.");
|
||||
addLog(name() + " drafted " + bestPick.getDisplayName() + " face up.");
|
||||
if (!alreadyRevealed) {
|
||||
showRevealedCard(bestPick);
|
||||
}
|
||||
@@ -564,7 +564,7 @@ public class LimitedPlayer {
|
||||
List<String> note = noted.computeIfAbsent(found.getName(), k -> Lists.newArrayList());
|
||||
revealed.add(bestPick);
|
||||
note.add(bestPick.getName());
|
||||
addLog(name() + " revealed " + bestPick.getName() + " and noted its name for Noble Banneret.");
|
||||
addLog(name() + " revealed " + bestPick.getDisplayName() + " and noted its name for Noble Banneret.");
|
||||
addLog(name() + " has flipped Noble Banneret face down.");
|
||||
alreadyRevealed = true;
|
||||
|
||||
@@ -613,7 +613,7 @@ public class LimitedPlayer {
|
||||
List<String> note = noted.computeIfAbsent(found.getName(), k -> Lists.newArrayList());
|
||||
revealed.add(bestPick);
|
||||
note.addAll(bestPick.getRules().getType().getCreatureTypes());
|
||||
addLog(name() + " revealed " + bestPick.getName() + " and noted - " + TextUtil.join(bestPick.getRules().getType().getCreatureTypes(), ",") + " for Paliano Vanguard.");
|
||||
addLog(name() + " revealed " + bestPick.getDisplayName() + " and noted - " + TextUtil.join(bestPick.getRules().getType().getCreatureTypes(), ",") + " for Paliano Vanguard.");
|
||||
addLog(name() + " has flipped Paliano Vanguard face down.");
|
||||
alreadyRevealed = true;
|
||||
|
||||
@@ -702,12 +702,12 @@ public class LimitedPlayer {
|
||||
LimitedPlayer guesser = pack.getAwaitingGuess().getKey();
|
||||
PaperCard guess = pack.getAwaitingGuess().getValue();
|
||||
|
||||
addLog(name() + " reveals " + drafted.getName() + " from " + guesser.name() + "'s guess of " + guess.getName() + " with Spire Phantasm.");
|
||||
addLog(name() + " reveals " + drafted.getDisplayName() + " from " + guesser.name() + "'s guess of " + guess.getDisplayName() + " with Spire Phantasm.");
|
||||
if (guess.equals(drafted)) {
|
||||
addLog(guesser.name() + " correctly guessed " + guess.getName() + " with Spire Phantasm.");
|
||||
addLog(guesser.name() + " correctly guessed " + guess.getDisplayName() + " with Spire Phantasm.");
|
||||
guesser.getDraftNotes().computeIfAbsent("Spire Phantasm", k -> Lists.newArrayList()).add(guess.getName());
|
||||
} else {
|
||||
addLog(guesser.name() + " incorrectly guessed " + guess.getName() + " with Spire Phantasm.");
|
||||
addLog(guesser.name() + " incorrectly guessed " + guess.getDisplayName() + " with Spire Phantasm.");
|
||||
}
|
||||
|
||||
pack.resetAwaitingGuess();
|
||||
@@ -774,7 +774,7 @@ public class LimitedPlayer {
|
||||
continue;
|
||||
}
|
||||
|
||||
addLog(player.name() + " offered " + offer.getName() + " to " + name() + " for " + exchangeCard.getName());
|
||||
addLog(player.name() + " offered " + offer.getDisplayName() + " to " + name() + " for " + exchangeCard.getName());
|
||||
offers.put(offer, player);
|
||||
}
|
||||
|
||||
@@ -795,11 +795,11 @@ public class LimitedPlayer {
|
||||
return SGuiChoose.oneOrNone("Choose a card to offer for trade: ", deckCards);
|
||||
}
|
||||
|
||||
return SGuiChoose.oneOrNone("Choose a card to trade for " + offer.getName() + ": ", deckCards);
|
||||
return SGuiChoose.oneOrNone("Choose a card to trade for " + offer.getDisplayName() + ": ", deckCards);
|
||||
}
|
||||
|
||||
protected PaperCard chooseCardToExchange(PaperCard exchangeCard, Map<PaperCard, LimitedPlayer> offers) {
|
||||
return SGuiChoose.oneOrNone("Choose a card to accept trade of " + exchangeCard + ": ", offers.keySet(), null, (card) -> card.getName() + " (" + offers.get(card).getName() + ")");
|
||||
return SGuiChoose.oneOrNone("Choose a card to accept trade of " + exchangeCard + ": ", offers.keySet(), null, (card) -> card.getDisplayName() + " (" + offers.get(card).getName() + ")");
|
||||
}
|
||||
|
||||
protected void exchangeAcceptedOffer(PaperCard exchangeCard, LimitedPlayer player, PaperCard offer) {
|
||||
|
||||
@@ -68,8 +68,18 @@ public class ConquestCommander implements InventoryItem, IXmlWritable {
|
||||
return card.getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDisplayName() {
|
||||
return card.getDisplayName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasFlavorName() {
|
||||
return card.hasFlavorName();
|
||||
}
|
||||
|
||||
public String getPlayerName() {
|
||||
String name = card.getName();
|
||||
String name = card.getDisplayName();
|
||||
int idx = name.indexOf(',');
|
||||
if (idx != -1) { //trim everything after the comma
|
||||
name = name.substring(0, idx);
|
||||
|
||||
@@ -291,16 +291,16 @@ public final class ConquestData {
|
||||
commandersBeingExiled.add(commander); //cache commander to make it easier to remove later
|
||||
}
|
||||
if (commander.getDeck().getMain().contains(card)) {
|
||||
commandersUsingCard.append("\n").append(CardTranslation.getTranslatedName(commander.getName()));
|
||||
commandersUsingCard.append("\n").append(CardTranslation.getTranslatedName(commander.getDisplayName()));
|
||||
}
|
||||
}
|
||||
// Android API StringBuilder isEmpty() is unavailable. https://developer.android.com/reference/java/lang/StringBuilder
|
||||
if (commandersUsingCard.length() != 0) {
|
||||
SOptionPane.showMessageDialog(Localizer.getInstance().getMessage("lblCommandersCardCannotBeExiledByCard", CardTranslation.getTranslatedName(card.getName()), commandersUsingCard), title, SOptionPane.INFORMATION_ICON);
|
||||
SOptionPane.showMessageDialog(Localizer.getInstance().getMessage("lblCommandersCardCannotBeExiledByCard", CardTranslation.getTranslatedName(card.getDisplayName()), commandersUsingCard), title, SOptionPane.INFORMATION_ICON);
|
||||
return false;
|
||||
}
|
||||
|
||||
message.append("\n").append(CardTranslation.getTranslatedName(card.getName()));
|
||||
message.append("\n").append(CardTranslation.getTranslatedName(card.getDisplayName()));
|
||||
}
|
||||
|
||||
if (SOptionPane.showConfirmDialog(message.toString(), title, Localizer.getInstance().getMessage("lblOK"), Localizer.getInstance().getMessage("lblCancel"))) {
|
||||
|
||||
@@ -143,7 +143,7 @@ public class QuestTournamentController {
|
||||
final PaperCard card = GuiBase.getInterface().chooseCard(localizer.getMessage("lblSelectACard"), localizer.getMessage("lblSelectKeepCard"), prizes.selectRareCards);
|
||||
prizes.addSelectedCard(card);
|
||||
|
||||
SOptionPane.showMessageDialog("'" + card.getName() + "' " + localizer.getMessage("lblAddToCollection"), localizer.getMessage("lblCardAdded"), FSkinProp.ICO_QUEST_STAKES);
|
||||
SOptionPane.showMessageDialog("'" + card.getDisplayName() + "' " + localizer.getMessage("lblAddToCollection"), localizer.getMessage("lblCardAdded"), FSkinProp.ICO_QUEST_STAKES);
|
||||
}
|
||||
|
||||
if (draft.getPlayerPlacement() == 1) {
|
||||
|
||||
@@ -153,7 +153,7 @@ public class CardDetailUtil {
|
||||
if (item instanceof PreconDeck) {
|
||||
return ((PreconDeck) item).getDescription();
|
||||
}
|
||||
return item.getName();
|
||||
return item.getDisplayName();
|
||||
}
|
||||
|
||||
public static String formatCardName(final CardView card, final boolean canShow, final boolean forAltState) {
|
||||
@@ -245,13 +245,13 @@ public class CardDetailUtil {
|
||||
PaperCard origPaperCard = null;
|
||||
Card origCard = null;
|
||||
try {
|
||||
if (!card.getName().isEmpty()) {
|
||||
origPaperCard = FModel.getMagicDb().getCommonCards().getCard(card.getName());
|
||||
if (!card.getOracleName().isEmpty()) {
|
||||
origPaperCard = FModel.getMagicDb().getCommonCards().getCard(card.getOracleName());
|
||||
} else {
|
||||
// probably a morph or manifest, try to get its identity from the alternate state
|
||||
String altName = card.getAlternateState().getName();
|
||||
String altName = card.getAlternateState().getOracleName();
|
||||
if (!altName.isEmpty()) {
|
||||
origPaperCard = FModel.getMagicDb().getCommonCards().getCard(card.getAlternateState().getName());
|
||||
origPaperCard = FModel.getMagicDb().getCommonCards().getCard(altName);
|
||||
}
|
||||
}
|
||||
if (origPaperCard != null) {
|
||||
@@ -259,7 +259,7 @@ public class CardDetailUtil {
|
||||
}
|
||||
origIdent = origCard != null ? getCurrentColors(origCard.isFaceDown() ? CardView.get(origCard).getState(false) : CardView.get(origCard).getCurrentState()) : "";
|
||||
} catch(Exception ex) {
|
||||
System.err.println("Unexpected behavior: card " + card.getName() + "[" + card.getId() + "] tripped an exception when trying to process current card colors.");
|
||||
System.err.println("Unexpected behavior: card " + card.getOracleName() + "[" + card.getId() + "] tripped an exception when trying to process current card colors.");
|
||||
}
|
||||
isChanged = !curColors.equals(origIdent);
|
||||
}
|
||||
@@ -420,7 +420,7 @@ public class CardDetailUtil {
|
||||
if (pl != null) {
|
||||
Map<String, String> notes = pl.getDraftNotes();
|
||||
if (notes != null) {
|
||||
String note = notes.get(card.getName());
|
||||
String note = notes.get(card.getOracleName());
|
||||
if (note != null) {
|
||||
area.append("\n");
|
||||
area.append("Draft Notes: ").append(note);
|
||||
|
||||
@@ -60,17 +60,7 @@ public class AdvancedSearch {
|
||||
|
||||
@Override
|
||||
protected Set<String> getItemValues(PaperCard input) {
|
||||
Set<String> names = new HashSet<>();
|
||||
names.add(input.getName());
|
||||
names.add(CardTranslation.getTranslatedName(input.getName()));
|
||||
CardSplitType cardSplitType = input.getRules().getSplitType();
|
||||
if (cardSplitType != CardSplitType.None && cardSplitType != CardSplitType.Split) {
|
||||
if (input.getRules().getOtherPart() != null) {
|
||||
names.add(input.getRules().getOtherPart().getName());
|
||||
names.add(CardTranslation.getTranslatedName(input.getRules().getOtherPart().getName()));
|
||||
}
|
||||
}
|
||||
return names;
|
||||
return input.getAllSearchableNames();
|
||||
}
|
||||
}),
|
||||
CARD_RULES_TEXT("lblRulesText", PaperCard.class, FilterOperator.STRINGS_OPS, new StringEvaluator<PaperCard>() {
|
||||
@@ -310,7 +300,7 @@ public class AdvancedSearch {
|
||||
INVITEM_NAME("lblName", InventoryItem.class, FilterOperator.STRING_OPS, new StringEvaluator<InventoryItem>() {
|
||||
@Override
|
||||
protected String getItemValue(InventoryItem input) {
|
||||
return input.getName();
|
||||
return input.getDisplayName();
|
||||
}
|
||||
}),
|
||||
INVITEM_RULES_TEXT("lblRulesText", InventoryItem.class, FilterOperator.STRING_OPS, new StringEvaluator<InventoryItem>() {
|
||||
@@ -573,7 +563,7 @@ public class AdvancedSearch {
|
||||
DECK_NAME("lblName", DeckProxy.class, FilterOperator.STRING_OPS, new StringEvaluator<DeckProxy>() {
|
||||
@Override
|
||||
protected String getItemValue(DeckProxy input) {
|
||||
return input.getName();
|
||||
return input.getDisplayName();
|
||||
}
|
||||
}),
|
||||
DECK_FOLDER("lblFolder", DeckProxy.class, FilterOperator.STRING_OPS, new StringEvaluator<DeckProxy>() {
|
||||
@@ -675,7 +665,7 @@ public class AdvancedSearch {
|
||||
COMMANDER_NAME("lblName", ConquestCommander.class, FilterOperator.STRING_OPS, new StringEvaluator<ConquestCommander>() {
|
||||
@Override
|
||||
protected String getItemValue(ConquestCommander input) {
|
||||
return input.getName();
|
||||
return input.getDisplayName();
|
||||
}
|
||||
}),
|
||||
COMMANDER_ORIGIN("lblOrigin", ConquestCommander.class, FilterOperator.SINGLE_LIST_OPS, new CustomListEvaluator<ConquestCommander, ConquestPlane>(ImmutableList.copyOf(FModel.getPlanes())) {
|
||||
@@ -1391,7 +1381,7 @@ public class AdvancedSearch {
|
||||
|
||||
Integer amount = -1;
|
||||
if (operator == FilterOperator.CONTAINS_X_COPIES_OF_CARD) { //prompt for quantity if needed
|
||||
amount = SGuiChoose.getInteger(Localizer.getInstance().getMessage("lblHowManyCopiesOfN", CardTranslation.getTranslatedName(card.getName())), 0, 4);
|
||||
amount = SGuiChoose.getInteger(Localizer.getInstance().getMessage("lblHowManyCopiesOfN", CardTranslation.getTranslatedName(card.getDisplayName())), 0, 4);
|
||||
if (amount == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -287,23 +287,6 @@ public abstract class AdvancedSearchParser {
|
||||
}
|
||||
break;
|
||||
|
||||
case "name":
|
||||
switch(opUsed) {
|
||||
case "!":
|
||||
predicate = CardRulesPredicates.name(StringOp.EQUALS_IC, valueStr);
|
||||
break;
|
||||
|
||||
case "!=":
|
||||
predicate = CardRulesPredicates.name(StringOp.EQUALS_IC, valueStr).negate();
|
||||
break;
|
||||
|
||||
case "=":
|
||||
case ":":
|
||||
predicate = CardRulesPredicates.name(StringOp.CONTAINS_IC, valueStr);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case "is":
|
||||
if (opUsed.equals(":")) {
|
||||
switch(valueStr) {
|
||||
@@ -444,6 +427,25 @@ public abstract class AdvancedSearchParser {
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
|
||||
case "name":
|
||||
switch(opUsed) {
|
||||
case "!":
|
||||
predicate = PaperCardPredicates.searchableName(StringOp.EQUALS_IC, valueStr);
|
||||
break;
|
||||
|
||||
case "!=":
|
||||
predicate = PaperCardPredicates.searchableName(StringOp.EQUALS_IC, valueStr).negate();
|
||||
break;
|
||||
|
||||
case "=":
|
||||
case ":":
|
||||
predicate = PaperCardPredicates.searchableName(StringOp.CONTAINS_IC, valueStr);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case "is":
|
||||
if (opUsed.equals(":")) {
|
||||
switch(valueStr) {
|
||||
|
||||
@@ -56,14 +56,14 @@ public enum ColumnDef {
|
||||
if (from.getKey() instanceof PaperCard) {
|
||||
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;
|
||||
return sortableName == null ? TextUtil.toSortableName(from.getKey().getDisplayName() + spire) : sortableName + spire;
|
||||
}
|
||||
return TextUtil.toSortableName(from.getKey().getName());
|
||||
return TextUtil.toSortableName(from.getKey().getDisplayName());
|
||||
},
|
||||
from -> {
|
||||
if (from.getKey() instanceof PaperCard)
|
||||
return from.getKey().toString();
|
||||
return from.getKey().getName();
|
||||
return CardTranslation.getTranslatedName(from.getKey().getDisplayName());
|
||||
return from.getKey().getDisplayName();
|
||||
}),
|
||||
|
||||
/**
|
||||
|
||||
@@ -155,33 +155,28 @@ public class SFilterUtil {
|
||||
}
|
||||
}
|
||||
|
||||
Predicate<CardRules> textFilter;
|
||||
if (advancedCardRulesPredicates.isEmpty()) {
|
||||
if (BooleanExpression.isExpression(segment)) {
|
||||
if (advancedCardRulesPredicates.isEmpty() && BooleanExpression.isExpression(segment)) {
|
||||
BooleanExpression expression = new BooleanExpression(segment, inName, inType, inText, inCost);
|
||||
|
||||
try {
|
||||
Predicate<CardRules> filter = expression.evaluate();
|
||||
if (filter != null) {
|
||||
textFilter = filter;
|
||||
} else {
|
||||
textFilter = buildRegularTextPredicate(regularTokens, inName, inType, inText, inCost);
|
||||
if(advancedPaperCardPredicates.isEmpty())
|
||||
return PaperCardPredicates.fromRules(filter);
|
||||
return IterableUtil.and(advancedPaperCardPredicates).and(PaperCardPredicates.fromRules(filter));
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
textFilter = buildRegularTextPredicate(regularTokens, inName, inType, inText, inCost);
|
||||
}
|
||||
} else {
|
||||
textFilter = buildRegularTextPredicate(regularTokens, inName, inType, inText, inCost);
|
||||
}
|
||||
} else {
|
||||
Predicate<CardRules> advancedCardRulesPredicate = IterableUtil.and(advancedCardRulesPredicates);
|
||||
Predicate<CardRules> regularPredicate = buildRegularTextPredicate(regularTokens, inName, inType, inText, inCost);
|
||||
textFilter = advancedCardRulesPredicate.and(regularPredicate);
|
||||
}
|
||||
|
||||
return PaperCardPredicates.fromRules(textFilter).and(IterableUtil.and(advancedPaperCardPredicates));
|
||||
Predicate<PaperCard> cardFilter = buildRegularTextPredicate(regularTokens, inName, inType, inText, inCost);
|
||||
if(!advancedPaperCardPredicates.isEmpty())
|
||||
cardFilter = cardFilter.and(IterableUtil.and(advancedPaperCardPredicates));
|
||||
if(!advancedCardRulesPredicates.isEmpty())
|
||||
cardFilter = cardFilter.and(PaperCardPredicates.fromRules(IterableUtil.and(advancedCardRulesPredicates)));
|
||||
|
||||
return cardFilter;
|
||||
}
|
||||
|
||||
private static List<String> getSplitText(String text) {
|
||||
@@ -224,21 +219,28 @@ public class SFilterUtil {
|
||||
return splitText;
|
||||
}
|
||||
|
||||
private static Predicate<CardRules> buildRegularTextPredicate(List<String> tokens, boolean inName, boolean inType, boolean inText, boolean inCost) {
|
||||
private static Predicate<PaperCard> buildRegularTextPredicate(List<String> tokens, boolean inName, boolean inType, boolean inText, boolean inCost) {
|
||||
if (tokens.isEmpty()) {
|
||||
return x -> true;
|
||||
}
|
||||
|
||||
List<Predicate<CardRules>> terms = new ArrayList<>();
|
||||
List<Predicate<PaperCard>> terms = new ArrayList<>();
|
||||
for (String s : tokens) {
|
||||
List<Predicate<CardRules>> subands = new ArrayList<>();
|
||||
|
||||
if (inName) { subands.add(CardRulesPredicates.name(StringOp.CONTAINS_IC, s)); }
|
||||
if (inType) { subands.add(CardRulesPredicates.joinedType(StringOp.CONTAINS_IC, s)); }
|
||||
if (inText) { subands.add(CardRulesPredicates.rules(StringOp.CONTAINS_IC, s)); }
|
||||
if (inCost) { subands.add(CardRulesPredicates.cost(StringOp.CONTAINS_IC, s)); }
|
||||
|
||||
terms.add(IterableUtil.or(subands));
|
||||
Predicate<PaperCard> term;
|
||||
if (inName && subands.isEmpty())
|
||||
term = PaperCardPredicates.searchableName(StringOp.CONTAINS_IC, s);
|
||||
else if (inName)
|
||||
term = PaperCardPredicates.searchableName(StringOp.CONTAINS_IC, s).or(PaperCardPredicates.fromRules(IterableUtil.or(subands)));
|
||||
else
|
||||
term = PaperCardPredicates.fromRules(IterableUtil.or(subands));
|
||||
|
||||
terms.add(term);
|
||||
}
|
||||
return IterableUtil.and(terms);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user