mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-11 16:26:22 +00:00
Merge branch 'master' into setEventCommand
# Conflicts: # forge-gui-mobile/src/forge/adventure/data/AdventureEventData.java # forge-gui-mobile/src/forge/adventure/stage/MapStage.java # forge-gui-mobile/src/forge/adventure/util/AdventureEventController.java
This commit is contained in:
@@ -31,6 +31,8 @@ public final class ImageKeys {
|
||||
public static final String MONARCH_IMAGE = "monarch";
|
||||
public static final String THE_RING_IMAGE = "the_ring";
|
||||
public static final String RADIATION_IMAGE = "radiation";
|
||||
public static final String SPEED_IMAGE = "speed";
|
||||
public static final String MAX_SPEED_IMAGE = "max_speed";
|
||||
|
||||
public static final String BACKFACE_POSTFIX = "$alt";
|
||||
public static final String SPECFACE_W = "$wspec";
|
||||
|
||||
@@ -29,8 +29,6 @@ import java.util.stream.Collectors;
|
||||
public class StaticData {
|
||||
private final CardStorageReader cardReader;
|
||||
private final CardStorageReader tokenReader;
|
||||
private final CardStorageReader customCardReader;
|
||||
|
||||
private final String blockDataFolder;
|
||||
private final CardDb commonCards;
|
||||
private final CardDb variantCards;
|
||||
@@ -79,7 +77,6 @@ public class StaticData {
|
||||
this.tokenReader = tokenReader;
|
||||
this.editions = new CardEdition.Collection(new CardEdition.Reader(new File(editionFolder)));
|
||||
this.blockDataFolder = blockDataFolder;
|
||||
this.customCardReader = customCardReader;
|
||||
this.allowCustomCardsInDecksConformance = allowCustomCardsInDecksConformance;
|
||||
this.enableSmartCardArtSelection = enableSmartCardArtSelection;
|
||||
this.loadNonLegalCards = loadNonLegalCards;
|
||||
@@ -881,7 +878,7 @@ public class StaticData {
|
||||
}
|
||||
}
|
||||
}
|
||||
// stream().toList() causes crash on Android, use Collectors.toList()
|
||||
// stream().toList() causes crash on Android 8-13, use Collectors.toList()
|
||||
List<String> NIF = new ArrayList<>(NIF_Q).stream().sorted().collect(Collectors.toList());
|
||||
List<String> CNI = new ArrayList<>(CNI_Q).stream().sorted().collect(Collectors.toList());
|
||||
List<String> TOK = new ArrayList<>(TOKEN_Q).stream().sorted().collect(Collectors.toList());
|
||||
|
||||
@@ -45,8 +45,6 @@ public final class CardDb implements ICardDatabase, IDeckGenPool {
|
||||
public final static char NameSetSeparator = '|';
|
||||
public final static String FlagPrefix = "#";
|
||||
public static final String FlagSeparator = "\t";
|
||||
private final String exlcudedCardName = "Concentrate";
|
||||
private final String exlcudedCardSet = "DS0";
|
||||
|
||||
// need this to obtain cardReference by name+set+artindex
|
||||
private final ListMultimap<String, PaperCard> allCardsByName = Multimaps.newListMultimap(new TreeMap<>(String.CASE_INSENSITIVE_ORDER), Lists::newArrayList);
|
||||
@@ -303,7 +301,7 @@ public final class CardDb implements ICardDatabase, IDeckGenPool {
|
||||
|
||||
// create faces list from rules
|
||||
for (final CardRules rule : rules.values()) {
|
||||
if (filteredCards.contains(rule.getName()) && !exlcudedCardName.equalsIgnoreCase(rule.getName()))
|
||||
if (filteredCards.contains(rule.getName()))
|
||||
continue;
|
||||
for (ICardFace face : rule.getAllFaces()) {
|
||||
addFaceToDbNames(face);
|
||||
@@ -501,8 +499,9 @@ public final class CardDb implements ICardDatabase, IDeckGenPool {
|
||||
}
|
||||
|
||||
public void addCard(PaperCard paperCard) {
|
||||
if (excludeCard(paperCard.getName(), paperCard.getEdition()))
|
||||
if (filtered.contains(paperCard.getName())) {
|
||||
return;
|
||||
}
|
||||
|
||||
allCardsByName.put(paperCard.getName(), paperCard);
|
||||
|
||||
@@ -523,17 +522,6 @@ public final class CardDb implements ICardDatabase, IDeckGenPool {
|
||||
}
|
||||
}
|
||||
|
||||
private boolean excludeCard(String cardName, String cardEdition) {
|
||||
if (filtered.isEmpty())
|
||||
return false;
|
||||
if (filtered.contains(cardName)) {
|
||||
if (exlcudedCardSet.equalsIgnoreCase(cardEdition) && exlcudedCardName.equalsIgnoreCase(cardName))
|
||||
return true;
|
||||
else return !exlcudedCardName.equalsIgnoreCase(cardName);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private void reIndex() {
|
||||
uniqueCardsByName.clear();
|
||||
for (Entry<String, Collection<PaperCard>> kv : allCardsByName.asMap().entrySet()) {
|
||||
|
||||
@@ -52,6 +52,14 @@ import java.util.stream.Collectors;
|
||||
*/
|
||||
public final class CardEdition implements Comparable<CardEdition> {
|
||||
|
||||
public DraftOptions getDraftOptions() {
|
||||
return draftOptions;
|
||||
}
|
||||
|
||||
public void setDraftOptions(DraftOptions draftOptions) {
|
||||
this.draftOptions = draftOptions;
|
||||
}
|
||||
|
||||
// immutable
|
||||
public enum Type {
|
||||
UNKNOWN,
|
||||
@@ -275,18 +283,22 @@ public final class CardEdition implements Comparable<CardEdition> {
|
||||
// Booster/draft info
|
||||
private List<BoosterSlot> boosterSlots = null;
|
||||
private boolean smallSetOverride = false;
|
||||
private boolean foilAlwaysInCommonSlot = false;
|
||||
private String additionalUnlockSet = "";
|
||||
private FoilType foilType = FoilType.NOT_SUPPORTED;
|
||||
|
||||
// Replace all of these things with booster slots
|
||||
private boolean foilAlwaysInCommonSlot = false;
|
||||
private double foilChanceInBooster = 0;
|
||||
private double chanceReplaceCommonWith = 0;
|
||||
private String slotReplaceCommonWith = "Common";
|
||||
private String additionalSheetForFoils = "";
|
||||
private String additionalUnlockSet = "";
|
||||
private String boosterMustContain = "";
|
||||
private String boosterReplaceSlotFromPrintSheet = "";
|
||||
private String sheetReplaceCardFromSheet = "";
|
||||
private String sheetReplaceCardFromSheet2 = "";
|
||||
private String doublePickDuringDraft = "";
|
||||
|
||||
// Draft options
|
||||
private DraftOptions draftOptions = null;
|
||||
private String[] chaosDraftThemes = new String[0];
|
||||
|
||||
private final ListMultimap<String, EditionEntry> cardMap;
|
||||
@@ -373,7 +385,6 @@ public final class CardEdition implements Comparable<CardEdition> {
|
||||
public String getSlotReplaceCommonWith() { return slotReplaceCommonWith; }
|
||||
public String getAdditionalSheetForFoils() { return additionalSheetForFoils; }
|
||||
public String getAdditionalUnlockSet() { return additionalUnlockSet; }
|
||||
public String getDoublePickDuringDraft() { return doublePickDuringDraft; }
|
||||
public String getBoosterMustContain() { return boosterMustContain; }
|
||||
public String getBoosterReplaceSlotFromPrintSheet() { return boosterReplaceSlotFromPrintSheet; }
|
||||
public String getSheetReplaceCardFromSheet() { return sheetReplaceCardFromSheet; }
|
||||
@@ -619,7 +630,7 @@ public final class CardEdition implements Comparable<CardEdition> {
|
||||
* functional variant name - grouping #9
|
||||
*/
|
||||
// "(^(.?[0-9A-Z]+.?))?(([SCURML]) )?(.*)$"
|
||||
"(^(.?[0-9A-Z-]+\\S?[A-Z]*)\\s)?(([SCURML])\\s)?([^@\\$]*)( @([^\\$]*))?( \\$(.+))?$"
|
||||
"(^(.?[0-9A-Z-]+\\S*[A-Z]*)\\s)?(([SCURML])\\s)?([^@\\$]*)( @([^\\$]*))?( \\$(.+))?$"
|
||||
);
|
||||
|
||||
final Pattern tokenPattern = Pattern.compile(
|
||||
@@ -628,7 +639,7 @@ public final class CardEdition implements Comparable<CardEdition> {
|
||||
* name - grouping #3
|
||||
* artist name - grouping #5
|
||||
*/
|
||||
"(^(.?[0-9A-Z-]+\\S?[A-Z]*)\\s)?([^@]*)( @(.*))?$"
|
||||
"(^(.?[0-9A-Z-]+\\S?[A-Z☇]*)\\s)?([^@]*)( @(.*))?$"
|
||||
);
|
||||
|
||||
ListMultimap<String, EditionEntry> cardMap = ArrayListMultimap.create();
|
||||
@@ -649,31 +660,37 @@ public final class CardEdition implements Comparable<CardEdition> {
|
||||
continue;
|
||||
}
|
||||
|
||||
// parse sections of the format "<collector number> <rarity> <name>"
|
||||
if (editionSectionsWithCollectorNumbers.contains(sectionName)) {
|
||||
for(String line : contents.get(sectionName)) {
|
||||
Matcher matcher = 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);
|
||||
|
||||
cardMap.put(sectionName, cis);
|
||||
}
|
||||
} else if (boosterSlotsToParse.contains(sectionName)) {
|
||||
// parse booster slots of the format "Base=N\n|Replace=<amount> <sheet>"
|
||||
boosterSlots.add(BoosterSlot.parseSlot(sectionName, contents.get(sectionName)));
|
||||
if (sectionName.endsWith("Types")) {
|
||||
CardType.Helper.parseTypes(sectionName, contents.get(sectionName));
|
||||
} else {
|
||||
// save custom print sheets of the format "<amount> <name>|<setcode>|<art index>"
|
||||
// to parse later when printsheets are loaded lazily (and the cardpool is already initialized)
|
||||
customPrintSheetsToParse.put(sectionName, contents.get(sectionName));
|
||||
// Parse cards
|
||||
|
||||
// parse sections of the format "<collector number> <rarity> <name>"
|
||||
if (editionSectionsWithCollectorNumbers.contains(sectionName)) {
|
||||
for(String line : contents.get(sectionName)) {
|
||||
Matcher matcher = 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);
|
||||
|
||||
cardMap.put(sectionName, cis);
|
||||
}
|
||||
} else if (boosterSlotsToParse.contains(sectionName)) {
|
||||
// parse booster slots of the format "Base=N\n|Replace=<amount> <sheet>"
|
||||
boosterSlots.add(BoosterSlot.parseSlot(sectionName, contents.get(sectionName)));
|
||||
} else {
|
||||
// save custom print sheets of the format "<amount> <name>|<setcode>|<art index>"
|
||||
// to parse later when printsheets are loaded lazily (and the cardpool is already initialized)
|
||||
customPrintSheetsToParse.put(sectionName, contents.get(sectionName));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -802,7 +819,6 @@ public final class CardEdition implements Comparable<CardEdition> {
|
||||
res.additionalUnlockSet = metadata.get("AdditionalSetUnlockedInQuest", ""); // e.g. Time Spiral Timeshifted (TSB) for Time Spiral
|
||||
|
||||
res.smallSetOverride = metadata.getBoolean("TreatAsSmallSet", false); // for "small" sets with over 200 cards (e.g. Eldritch Moon)
|
||||
res.doublePickDuringDraft = metadata.get("DoublePick", ""); // "FirstPick" or "Always"
|
||||
|
||||
res.boosterMustContain = metadata.get("BoosterMustContain", ""); // e.g. Dominaria guaranteed legendary creature
|
||||
res.boosterReplaceSlotFromPrintSheet = metadata.get("BoosterReplaceSlotFromPrintSheet", ""); // e.g. Zendikar Rising guaranteed double-faced card
|
||||
@@ -810,6 +826,23 @@ public final class CardEdition implements Comparable<CardEdition> {
|
||||
res.sheetReplaceCardFromSheet2 = metadata.get("SheetReplaceCardFromSheet2", "");
|
||||
res.chaosDraftThemes = metadata.get("ChaosDraftThemes", "").split(";"); // semicolon separated list of theme names
|
||||
|
||||
// Draft options
|
||||
String doublePick = metadata.get("DoublePick", "Never");
|
||||
int maxPodSize = metadata.getInt("MaxPodSize", 8);
|
||||
int recommendedPodSize = metadata.getInt("RecommendedPodSize", 8);
|
||||
int maxMatchPlayers = metadata.getInt("MaxMatchPlayers", 2);
|
||||
String deckType = metadata.get("DeckType", "Normal");
|
||||
String freeCommander = metadata.get("FreeCommander", "");
|
||||
|
||||
res.draftOptions = new DraftOptions(
|
||||
doublePick,
|
||||
maxPodSize,
|
||||
recommendedPodSize,
|
||||
maxMatchPlayers,
|
||||
deckType,
|
||||
freeCommander
|
||||
);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
@@ -840,7 +873,7 @@ public final class CardEdition implements Comparable<CardEdition> {
|
||||
@Override
|
||||
public void add(CardEdition item) { //Even though we want it to be read only, make an exception for custom content.
|
||||
if(lock) throw new UnsupportedOperationException("This is a read-only storage");
|
||||
else map.put(item.getName(), item);
|
||||
else map.put(item.getCode(), item);
|
||||
}
|
||||
public void append(CardEdition.Collection C){ //Append custom editions
|
||||
if (lock) throw new UnsupportedOperationException("This is a read-only storage");
|
||||
@@ -985,16 +1018,13 @@ public final class CardEdition implements Comparable<CardEdition> {
|
||||
|
||||
public static final Predicate<CardEdition> HAS_BOOSTER_BOX = edition -> edition.getBoosterBoxCount() > 0;
|
||||
|
||||
@Deprecated //Use CardEdition::hasBasicLands and a nonnull test.
|
||||
public static final Predicate<CardEdition> hasBasicLands = ed -> {
|
||||
if (ed == null) {
|
||||
// Happens for new sets with "???" code
|
||||
return false;
|
||||
}
|
||||
for(String landName : MagicColor.Constant.BASIC_LANDS) {
|
||||
if (null == StaticData.instance().getCommonCards().getCard(landName, ed.getCode(), 0))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
return ed.hasBasicLands();
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1015,7 +1045,7 @@ public final class CardEdition implements Comparable<CardEdition> {
|
||||
|
||||
public boolean hasBasicLands() {
|
||||
for(String landName : MagicColor.Constant.BASIC_LANDS) {
|
||||
if (null == StaticData.instance().getCommonCards().getCard(landName, this.getCode(), 0))
|
||||
if (this.getCardInSet(landName).isEmpty())
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
||||
@@ -53,6 +53,7 @@ public final class CardRules implements ICardCharacteristics {
|
||||
private boolean addsWildCardColor;
|
||||
private int setColorID;
|
||||
private boolean custom;
|
||||
private boolean unsupported;
|
||||
private String path;
|
||||
|
||||
public CardRules(ICardFace[] faces, CardSplitType altMode, CardAiHints cah) {
|
||||
@@ -167,21 +168,7 @@ public final class CardRules implements ICardCharacteristics {
|
||||
}
|
||||
|
||||
public boolean isTransformable() {
|
||||
if (CardSplitType.Transform == getSplitType()) {
|
||||
return true;
|
||||
}
|
||||
if (CardSplitType.Modal != getSplitType()) {
|
||||
return false;
|
||||
}
|
||||
for (ICardFace face : getAllFaces()) {
|
||||
for (String spell : face.getAbilities()) {
|
||||
if (spell.contains("AB$ SetState") && spell.contains("Mode$ Transform")) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
// TODO check keywords if needed
|
||||
}
|
||||
return false;
|
||||
return CardSplitType.Transform == getSplitType() || CardSplitType.Modal == getSplitType();
|
||||
}
|
||||
|
||||
public ICardFace getWSpecialize() {
|
||||
@@ -220,7 +207,9 @@ public final class CardRules implements ICardCharacteristics {
|
||||
}
|
||||
|
||||
public boolean isCustom() { return custom; }
|
||||
public void setCustom() { custom = true; }
|
||||
public void setCustom() { custom = true; }
|
||||
|
||||
public boolean isUnsupported() { return unsupported; }
|
||||
|
||||
@Override
|
||||
public CardType getType() {
|
||||
@@ -335,6 +324,15 @@ public final class CardRules implements ICardCharacteristics {
|
||||
}
|
||||
if (hasKeyword("Friends forever") && b.hasKeyword("Friends forever")) {
|
||||
legal = true; // Stranger Things Secret Lair gimmick partner commander
|
||||
}
|
||||
if (hasKeyword("Partner - Survivors") && b.hasKeyword("Partner - Survivors")) {
|
||||
legal = true; // The Last of Us Secret Lair gimmick partner commander
|
||||
}
|
||||
if (hasKeyword("Partner - Father & Son") && b.hasKeyword("Partner - Father & Son")) {
|
||||
legal = true; // God of War Secret Lair gimmick partner commander
|
||||
}
|
||||
if (hasKeyword("Partner - Character select") && b.hasKeyword("Partner - Character select")) {
|
||||
legal = true; // TMNT Commander deck gimmick partner commander
|
||||
}
|
||||
if (hasKeyword("Choose a Background") && b.canBeBackground()
|
||||
|| b.hasKeyword("Choose a Background") && canBeBackground()) {
|
||||
@@ -353,6 +351,7 @@ public final class CardRules implements ICardCharacteristics {
|
||||
}
|
||||
return canBeCommander() && (hasKeyword("Partner") || !this.partnerWith.isEmpty() ||
|
||||
hasKeyword("Friends forever") || hasKeyword("Choose a Background") ||
|
||||
hasKeyword("Partner - Father & Son") || hasKeyword("Partner - Survivors") || hasKeyword("Partner - Character select") ||
|
||||
hasKeyword("Doctor's companion") || isDoctor());
|
||||
}
|
||||
|
||||
@@ -373,6 +372,9 @@ public final class CardRules implements ICardCharacteristics {
|
||||
|
||||
public boolean canBeOathbreaker() {
|
||||
CardType type = mainPart.getType();
|
||||
if (mainPart.getOracleText().contains("can be your commander")) {
|
||||
return true;
|
||||
}
|
||||
return type.isPlaneswalker();
|
||||
}
|
||||
|
||||
@@ -825,6 +827,8 @@ public final class CardRules implements ICardCharacteristics {
|
||||
faces[0].assignMissingFields();
|
||||
final CardRules result = new CardRules(faces, CardSplitType.None, cah);
|
||||
|
||||
result.unsupported = true;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
@@ -196,6 +196,31 @@ public final class CardRulesPredicates {
|
||||
return card -> card.getSplitType().equals(type);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return a Predicate that matches cards that are vanilla.
|
||||
*/
|
||||
public static Predicate<CardRules> isVanilla() {
|
||||
return card -> {
|
||||
if (!(card.getType().isCreature() || card.getType().isLand()) ||
|
||||
card.getSplitType() != CardSplitType.None ||
|
||||
card.hasFunctionalVariants()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ICardFace mainPart = card.getMainPart();
|
||||
|
||||
boolean hasAny =
|
||||
mainPart.getKeywords().iterator().hasNext() ||
|
||||
mainPart.getAbilities().iterator().hasNext() ||
|
||||
mainPart.getStaticAbilities().iterator().hasNext() ||
|
||||
mainPart.getTriggers().iterator().hasNext() ||
|
||||
(mainPart.getDraftActions() != null && mainPart.getDraftActions().iterator().hasNext()) ||
|
||||
mainPart.getReplacements().iterator().hasNext();
|
||||
|
||||
return !hasAny;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks for color.
|
||||
*
|
||||
|
||||
@@ -1066,4 +1066,74 @@ public final class CardType implements Comparable<CardType>, CardTypeView {
|
||||
return type;
|
||||
}
|
||||
|
||||
public static class Helper {
|
||||
public static final void parseTypes(String sectionName, List<String> content) {
|
||||
Set<String> addToSection = null;
|
||||
|
||||
switch (sectionName) {
|
||||
case "BasicTypes":
|
||||
addToSection = CardType.Constant.BASIC_TYPES;
|
||||
break;
|
||||
case "LandTypes":
|
||||
addToSection = CardType.Constant.LAND_TYPES;
|
||||
break;
|
||||
case "CreatureTypes":
|
||||
addToSection = CardType.Constant.CREATURE_TYPES;
|
||||
break;
|
||||
case "SpellTypes":
|
||||
addToSection = CardType.Constant.SPELL_TYPES;
|
||||
break;
|
||||
case "EnchantmentTypes":
|
||||
addToSection = CardType.Constant.ENCHANTMENT_TYPES;
|
||||
break;
|
||||
case "ArtifactTypes":
|
||||
addToSection = CardType.Constant.ARTIFACT_TYPES;
|
||||
break;
|
||||
case "WalkerTypes":
|
||||
addToSection = CardType.Constant.WALKER_TYPES;
|
||||
break;
|
||||
case "DungeonTypes":
|
||||
addToSection = CardType.Constant.DUNGEON_TYPES;
|
||||
break;
|
||||
case "BattleTypes":
|
||||
addToSection = CardType.Constant.BATTLE_TYPES;
|
||||
break;
|
||||
case "PlanarTypes":
|
||||
addToSection = CardType.Constant.PLANAR_TYPES;
|
||||
break;
|
||||
}
|
||||
|
||||
if (addToSection == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
for(String line : content) {
|
||||
if (line.length() == 0) continue;
|
||||
|
||||
if (line.contains(":")) {
|
||||
String[] k = line.split(":");
|
||||
|
||||
if (addToSection.contains(k[0])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
addToSection.add(k[0]);
|
||||
CardType.Constant.pluralTypes.put(k[0], k[1]);
|
||||
|
||||
if (k[0].contains(" ")) {
|
||||
CardType.Constant.MultiwordTypes.add(k[0]);
|
||||
}
|
||||
} else {
|
||||
if (addToSection.contains(line)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
addToSection.add(line);
|
||||
if (line.contains(" ")) {
|
||||
CardType.Constant.MultiwordTypes.add(line);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,15 +17,12 @@
|
||||
*/
|
||||
package forge.card;
|
||||
|
||||
import com.google.common.collect.UnmodifiableIterator;
|
||||
import forge.card.MagicColor.Color;
|
||||
import forge.card.mana.ManaCost;
|
||||
import forge.card.mana.ManaCostShard;
|
||||
import forge.util.BinaryUtil;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
/**
|
||||
@@ -38,28 +35,64 @@ import java.util.stream.Stream;
|
||||
*
|
||||
*
|
||||
*/
|
||||
public final class ColorSet implements Comparable<ColorSet>, Iterable<Byte>, Serializable {
|
||||
private static final long serialVersionUID = 794691267379929080L;
|
||||
public enum ColorSet implements Iterable<Color>, Serializable {
|
||||
|
||||
private final byte myColor;
|
||||
C(Color.COLORLESS),
|
||||
W(Color.WHITE),
|
||||
U(Color.BLUE),
|
||||
WU(Color.WHITE, Color.BLUE),
|
||||
B(Color.BLACK),
|
||||
WB(Color.WHITE, Color.BLACK),
|
||||
UB(Color.BLUE, Color.BLACK),
|
||||
WUB(Color.WHITE, Color.BLUE, Color.BLACK),
|
||||
R(Color.RED),
|
||||
RW(Color.RED, Color.WHITE),
|
||||
UR(Color.BLUE, Color.RED),
|
||||
URW(Color.BLUE, Color.RED, Color.WHITE),
|
||||
BR(Color.BLACK, Color.RED),
|
||||
RWB(Color.RED, Color.WHITE, Color.BLACK),
|
||||
UBR(Color.BLUE, Color.BLACK, Color.RED),
|
||||
WUBR(Color.WHITE, Color.BLUE, Color.BLACK, Color.RED),
|
||||
G(Color.GREEN),
|
||||
GW(Color.GREEN, Color.WHITE),
|
||||
GU(Color.GREEN, Color.BLUE),
|
||||
GWU(Color.GREEN, Color.WHITE, Color.BLUE),
|
||||
BG(Color.BLACK, Color.GREEN),
|
||||
WBG(Color.WHITE, Color.BLACK, Color.GREEN),
|
||||
BGU(Color.BLACK, Color.GREEN, Color.BLUE),
|
||||
GWUB(Color.GREEN, Color.WHITE, Color.BLUE, Color.BLACK),
|
||||
RG(Color.RED, Color.GREEN),
|
||||
RGW(Color.RED, Color.GREEN, Color.WHITE),
|
||||
GUR(Color.GREEN, Color.BLUE, Color.RED),
|
||||
RGWU(Color.RED, Color.GREEN, Color.WHITE, Color.BLUE),
|
||||
BRG(Color.BLACK, Color.RED, Color.GREEN),
|
||||
BRGW(Color.BLACK, Color.RED, Color.GREEN, Color.WHITE),
|
||||
UBRG(Color.BLUE, Color.BLACK, Color.RED, Color.GREEN),
|
||||
WUBRG(Color.WHITE, Color.BLUE, Color.BLACK, Color.RED, Color.GREEN)
|
||||
;
|
||||
|
||||
private static final long serialVersionUID = 794691267379929080L;
|
||||
// needs to be before other static
|
||||
|
||||
private final Collection<Color> orderedShards;
|
||||
private final float orderWeight;
|
||||
|
||||
private static final ColorSet[] cache = new ColorSet[32];
|
||||
|
||||
public static final ColorSet ALL_COLORS = fromMask(MagicColor.ALL_COLORS);
|
||||
private static final ColorSet NO_COLORS = fromMask(MagicColor.COLORLESS);
|
||||
|
||||
private ColorSet(final byte mask) {
|
||||
this.myColor = mask;
|
||||
this.orderWeight = this.getOrderWeight();
|
||||
private ColorSet(final Color... ordered) {
|
||||
this.orderedShards = Arrays.asList(ordered);
|
||||
this.orderWeight = this.calcOrderWeight();
|
||||
}
|
||||
|
||||
public static ColorSet fromMask(final int mask) {
|
||||
final int mask32 = mask & MagicColor.ALL_COLORS;
|
||||
if (cache[mask32] == null) {
|
||||
cache[mask32] = new ColorSet((byte) mask32);
|
||||
return values()[mask32];
|
||||
}
|
||||
|
||||
public static ColorSet fromEnums(final Color... colors) {
|
||||
byte mask = 0;
|
||||
for (Color e : colors) {
|
||||
mask |= e.getColorMask();
|
||||
}
|
||||
return cache[mask32];
|
||||
return fromMask(mask);
|
||||
}
|
||||
|
||||
public static ColorSet fromNames(final String... colors) {
|
||||
@@ -98,7 +131,10 @@ public final class ColorSet implements Comparable<ColorSet>, Iterable<Byte>, Ser
|
||||
* @return true, if successful
|
||||
*/
|
||||
public boolean hasAnyColor(final int colormask) {
|
||||
return (this.myColor & colormask) != 0;
|
||||
return (this.ordinal() & colormask) != 0;
|
||||
}
|
||||
public boolean hasAnyColor(final Color c) {
|
||||
return this.orderedShards.contains(c);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -109,12 +145,12 @@ public final class ColorSet implements Comparable<ColorSet>, Iterable<Byte>, Ser
|
||||
* @return true, if successful
|
||||
*/
|
||||
public boolean hasAllColors(final int colormask) {
|
||||
return (this.myColor & colormask) == colormask;
|
||||
return (this.ordinal() & colormask) == colormask;
|
||||
}
|
||||
|
||||
/** this has exactly the colors defined by operand. */
|
||||
public boolean hasExactlyColor(final int colormask) {
|
||||
return this.myColor == colormask;
|
||||
return this.ordinal() == colormask;
|
||||
}
|
||||
|
||||
/** this has no other colors except defined by operand. */
|
||||
@@ -124,17 +160,17 @@ public final class ColorSet implements Comparable<ColorSet>, Iterable<Byte>, Ser
|
||||
|
||||
/** this has no other colors except defined by operand. */
|
||||
public boolean hasNoColorsExcept(final int colormask) {
|
||||
return (this.myColor & ~colormask) == 0;
|
||||
return (this.ordinal() & ~colormask) == 0;
|
||||
}
|
||||
|
||||
/** This returns the colors that colormask contains that are not in color */
|
||||
public ColorSet getMissingColors(final byte colormask) {
|
||||
return fromMask(this.myColor & ~colormask);
|
||||
return fromMask(this.ordinal() & ~colormask);
|
||||
}
|
||||
|
||||
/** Operand has no other colors except defined by this. */
|
||||
public boolean containsAllColorsFrom(final int colorProfile) {
|
||||
return (~this.myColor & colorProfile) == 0;
|
||||
return (~this.ordinal() & colorProfile) == 0;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -143,7 +179,7 @@ public final class ColorSet implements Comparable<ColorSet>, Iterable<Byte>, Ser
|
||||
* @return the int
|
||||
*/
|
||||
public int countColors() {
|
||||
return BinaryUtil.bitCount(this.myColor);
|
||||
return BinaryUtil.bitCount(this.ordinal());
|
||||
} // bit count
|
||||
|
||||
// order has to be: W U B R G multi colorless - same as cards numbering
|
||||
@@ -153,7 +189,7 @@ public final class ColorSet implements Comparable<ColorSet>, Iterable<Byte>, Ser
|
||||
*
|
||||
* @return the order weight
|
||||
*/
|
||||
private float getOrderWeight() {
|
||||
private float calcOrderWeight() {
|
||||
float res = this.countColors();
|
||||
if (hasWhite()) {
|
||||
res += 0.0005f;
|
||||
@@ -172,6 +208,10 @@ public final class ColorSet implements Comparable<ColorSet>, Iterable<Byte>, Ser
|
||||
}
|
||||
return res;
|
||||
}
|
||||
public float getOrderWeight()
|
||||
{
|
||||
return orderWeight;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if is colorless.
|
||||
@@ -179,7 +219,7 @@ public final class ColorSet implements Comparable<ColorSet>, Iterable<Byte>, Ser
|
||||
* @return true, if is colorless
|
||||
*/
|
||||
public boolean isColorless() {
|
||||
return this.myColor == 0;
|
||||
return this == C;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -197,7 +237,7 @@ public final class ColorSet implements Comparable<ColorSet>, Iterable<Byte>, Ser
|
||||
* @return true, if is all colors
|
||||
*/
|
||||
public boolean isAllColors() {
|
||||
return this == ALL_COLORS;
|
||||
return this == WUBRG;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -217,17 +257,7 @@ public final class ColorSet implements Comparable<ColorSet>, Iterable<Byte>, Ser
|
||||
* @return true, if is equal
|
||||
*/
|
||||
public boolean isEqual(final byte color) {
|
||||
return color == this.myColor;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see java.lang.Comparable#compareTo(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public int compareTo(final ColorSet other) {
|
||||
return Float.compare(this.orderWeight, other.orderWeight);
|
||||
return color == this.ordinal();
|
||||
}
|
||||
|
||||
// Presets
|
||||
@@ -277,33 +307,13 @@ public final class ColorSet implements Comparable<ColorSet>, Iterable<Byte>, Ser
|
||||
}
|
||||
|
||||
public ColorSet inverse() {
|
||||
byte mask = this.myColor;
|
||||
byte mask = (byte)this.ordinal();
|
||||
mask ^= MagicColor.ALL_COLORS;
|
||||
return fromMask(mask);
|
||||
}
|
||||
|
||||
public byte getColor() {
|
||||
return myColor;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see java.lang.Object#toString()
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
final ManaCostShard[] orderedShards = getOrderedShards();
|
||||
return Arrays.stream(orderedShards).map(ManaCostShard::toShortString).collect(Collectors.joining());
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the null color.
|
||||
*
|
||||
* @return the nullColor
|
||||
*/
|
||||
public static ColorSet getNullColor() {
|
||||
return NO_COLORS;
|
||||
return (byte)ordinal();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -313,7 +323,7 @@ public final class ColorSet implements Comparable<ColorSet>, Iterable<Byte>, Ser
|
||||
* @return true, if successful
|
||||
*/
|
||||
public boolean sharesColorWith(final ColorSet ccOther) {
|
||||
return (this.myColor & ccOther.myColor) != 0;
|
||||
return (this.ordinal() & ccOther.ordinal()) != 0;
|
||||
}
|
||||
|
||||
public ColorSet getSharedColors(final ColorSet ccOther) {
|
||||
@@ -321,123 +331,24 @@ public final class ColorSet implements Comparable<ColorSet>, Iterable<Byte>, Ser
|
||||
}
|
||||
|
||||
public ColorSet getOffColors(final ColorSet ccOther) {
|
||||
return fromMask(~this.myColor & ccOther.myColor);
|
||||
return fromMask(~this.ordinal() & ccOther.ordinal());
|
||||
}
|
||||
|
||||
public Set<Color> toEnumSet() {
|
||||
if (isColorless()) {
|
||||
return EnumSet.of(Color.COLORLESS);
|
||||
}
|
||||
List<Color> list = new ArrayList<>();
|
||||
for (Color c : Color.values()) {
|
||||
if (hasAnyColor(c.getColormask())) {
|
||||
list.add(c);
|
||||
}
|
||||
}
|
||||
return EnumSet.copyOf(list);
|
||||
return EnumSet.copyOf(orderedShards);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<Byte> iterator() {
|
||||
return new ColorIterator();
|
||||
//@Override
|
||||
public Iterator<Color> iterator() {
|
||||
return this.orderedShards.iterator();
|
||||
}
|
||||
|
||||
private class ColorIterator extends UnmodifiableIterator<Byte> {
|
||||
int currentBit = -1;
|
||||
|
||||
private int getIndexOfNextColor(){
|
||||
int nextBit = currentBit + 1;
|
||||
while (nextBit < MagicColor.NUMBER_OR_COLORS) {
|
||||
if ((myColor & MagicColor.WUBRG[nextBit]) != 0) {
|
||||
break;
|
||||
}
|
||||
nextBit++;
|
||||
}
|
||||
return nextBit;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
return getIndexOfNextColor() < MagicColor.NUMBER_OR_COLORS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Byte next() {
|
||||
currentBit = getIndexOfNextColor();
|
||||
if (currentBit >= MagicColor.NUMBER_OR_COLORS) {
|
||||
throw new NoSuchElementException();
|
||||
}
|
||||
|
||||
return MagicColor.WUBRG[currentBit];
|
||||
}
|
||||
}
|
||||
|
||||
public Stream<MagicColor.Color> stream() {
|
||||
return this.toEnumSet().stream();
|
||||
public Stream<Color> stream() {
|
||||
return this.orderedShards.stream();
|
||||
}
|
||||
|
||||
//Get array of mana cost shards for color set in the proper order
|
||||
public ManaCostShard[] getOrderedShards() {
|
||||
return shardOrderLookup[myColor];
|
||||
}
|
||||
|
||||
private static final ManaCostShard[][] shardOrderLookup = new ManaCostShard[MagicColor.ALL_COLORS + 1][];
|
||||
static {
|
||||
byte COLORLESS = MagicColor.COLORLESS;
|
||||
byte WHITE = MagicColor.WHITE;
|
||||
byte BLUE = MagicColor.BLUE;
|
||||
byte BLACK = MagicColor.BLACK;
|
||||
byte RED = MagicColor.RED;
|
||||
byte GREEN = MagicColor.GREEN;
|
||||
ManaCostShard C = ManaCostShard.COLORLESS;
|
||||
ManaCostShard W = ManaCostShard.WHITE;
|
||||
ManaCostShard U = ManaCostShard.BLUE;
|
||||
ManaCostShard B = ManaCostShard.BLACK;
|
||||
ManaCostShard R = ManaCostShard.RED;
|
||||
ManaCostShard G = ManaCostShard.GREEN;
|
||||
|
||||
//colorless
|
||||
shardOrderLookup[COLORLESS] = new ManaCostShard[] { C };
|
||||
|
||||
//mono-color
|
||||
shardOrderLookup[WHITE] = new ManaCostShard[] { W };
|
||||
shardOrderLookup[BLUE] = new ManaCostShard[] { U };
|
||||
shardOrderLookup[BLACK] = new ManaCostShard[] { B };
|
||||
shardOrderLookup[RED] = new ManaCostShard[] { R };
|
||||
shardOrderLookup[GREEN] = new ManaCostShard[] { G };
|
||||
|
||||
//two-color
|
||||
shardOrderLookup[WHITE | BLUE] = new ManaCostShard[] { W, U };
|
||||
shardOrderLookup[WHITE | BLACK] = new ManaCostShard[] { W, B };
|
||||
shardOrderLookup[BLUE | BLACK] = new ManaCostShard[] { U, B };
|
||||
shardOrderLookup[BLUE | RED] = new ManaCostShard[] { U, R };
|
||||
shardOrderLookup[BLACK | RED] = new ManaCostShard[] { B, R };
|
||||
shardOrderLookup[BLACK | GREEN] = new ManaCostShard[] { B, G };
|
||||
shardOrderLookup[RED | GREEN] = new ManaCostShard[] { R, G };
|
||||
shardOrderLookup[RED | WHITE] = new ManaCostShard[] { R, W };
|
||||
shardOrderLookup[GREEN | WHITE] = new ManaCostShard[] { G, W };
|
||||
shardOrderLookup[GREEN | BLUE] = new ManaCostShard[] { G, U };
|
||||
|
||||
//three-color
|
||||
shardOrderLookup[WHITE | BLUE | BLACK] = new ManaCostShard[] { W, U, B };
|
||||
shardOrderLookup[WHITE | BLACK | GREEN] = new ManaCostShard[] { W, B, G };
|
||||
shardOrderLookup[BLUE | BLACK | RED] = new ManaCostShard[] { U, B, R };
|
||||
shardOrderLookup[BLUE | RED | WHITE] = new ManaCostShard[] { U, R, W };
|
||||
shardOrderLookup[BLACK | RED | GREEN] = new ManaCostShard[] { B, R, G };
|
||||
shardOrderLookup[BLACK | GREEN | BLUE] = new ManaCostShard[] { B, G, U };
|
||||
shardOrderLookup[RED | GREEN | WHITE] = new ManaCostShard[] { R, G, W };
|
||||
shardOrderLookup[RED | WHITE | BLACK] = new ManaCostShard[] { R, W, B };
|
||||
shardOrderLookup[GREEN | WHITE | BLUE] = new ManaCostShard[] { G, W, U };
|
||||
shardOrderLookup[GREEN | BLUE | RED] = new ManaCostShard[] { G, U, R };
|
||||
|
||||
//four-color
|
||||
shardOrderLookup[WHITE | BLUE | BLACK | RED] = new ManaCostShard[] { W, U, B, R };
|
||||
shardOrderLookup[BLUE | BLACK | RED | GREEN] = new ManaCostShard[] { U, B, R, G };
|
||||
shardOrderLookup[BLACK | RED | GREEN | WHITE] = new ManaCostShard[] { B, R, G, W };
|
||||
shardOrderLookup[RED | GREEN | WHITE | BLUE] = new ManaCostShard[] { R, G, W, U };
|
||||
shardOrderLookup[GREEN | WHITE | BLUE | BLACK] = new ManaCostShard[] { G, W, U, B };
|
||||
|
||||
//five-color
|
||||
shardOrderLookup[WHITE | BLUE | BLACK | RED | GREEN] = new ManaCostShard[] { W, U, B, R, G };
|
||||
public Collection<Color> getOrderedColors() {
|
||||
return orderedShards;
|
||||
}
|
||||
}
|
||||
|
||||
75
forge-core/src/main/java/forge/card/DraftOptions.java
Normal file
75
forge-core/src/main/java/forge/card/DraftOptions.java
Normal file
@@ -0,0 +1,75 @@
|
||||
package forge.card;
|
||||
|
||||
public class DraftOptions {
|
||||
public enum DoublePick {
|
||||
NEVER,
|
||||
FIRST_PICK, // only first pick each pack
|
||||
WHEN_POD_SIZE_IS_4, // only when pod size is 4, so you can pick two cards each time
|
||||
ALWAYS // each time you receive a pack, you can pick two cards
|
||||
};
|
||||
public enum DeckType {
|
||||
Normal, // Standard deck, usually 40 cards
|
||||
Commander // Special deck type for Commander format. Important for selection/construction
|
||||
}
|
||||
|
||||
private DoublePick doublePick = DoublePick.NEVER;
|
||||
private final int maxPodSize; // Usually 8, but could be smaller for cubes. I guess it could be larger too
|
||||
private final int recommendedPodSize; // Usually 8, but is 4 for new double pick
|
||||
private final int maxMatchPlayers; // Usually 2, but 4 for things like Commander or Conspiracy
|
||||
private final DeckType deckType; // Normal or Commander
|
||||
private final String freeCommander;
|
||||
|
||||
public DraftOptions(String doublePickOption, int maxPodSize, int recommendedPodSize, int maxMatchPlayers, String deckType, String freeCommander) {
|
||||
this.maxPodSize = maxPodSize;
|
||||
this.recommendedPodSize = recommendedPodSize;
|
||||
this.maxMatchPlayers = maxMatchPlayers;
|
||||
this.deckType = DeckType.valueOf(deckType);
|
||||
this.freeCommander = freeCommander;
|
||||
if (doublePickOption != null) {
|
||||
switch (doublePickOption.toLowerCase()) {
|
||||
case "firstpick":
|
||||
doublePick = DoublePick.FIRST_PICK;
|
||||
break;
|
||||
case "always":
|
||||
doublePick = DoublePick.ALWAYS;
|
||||
break;
|
||||
case "whenpodsizeis4":
|
||||
doublePick = DoublePick.WHEN_POD_SIZE_IS_4;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
public int getMaxPodSize() {
|
||||
return maxPodSize;
|
||||
}
|
||||
public int getRecommendedPodSize() {
|
||||
return recommendedPodSize;
|
||||
}
|
||||
public DoublePick getDoublePick() {
|
||||
return doublePick;
|
||||
}
|
||||
|
||||
public DoublePick isDoublePick(int podSize) {
|
||||
if (doublePick == DoublePick.WHEN_POD_SIZE_IS_4) {
|
||||
if (podSize != 4) {
|
||||
return DoublePick.NEVER;
|
||||
}
|
||||
// only when pod size is 4, so you can pick two cards each time
|
||||
return DoublePick.ALWAYS;
|
||||
}
|
||||
|
||||
return doublePick;
|
||||
}
|
||||
|
||||
|
||||
public int getMaxMatchPlayers() {
|
||||
return maxMatchPlayers;
|
||||
}
|
||||
public DeckType getDeckType() {
|
||||
return deckType;
|
||||
}
|
||||
public String getFreeCommander() {
|
||||
return freeCommander;
|
||||
}
|
||||
}
|
||||
@@ -75,8 +75,6 @@ public interface ICardDatabase extends Iterable<PaperCard> {
|
||||
PaperCard getCardFromEditionsReleasedAfter(String cardName, CardArtPreference artPreference, int artIndex, Date releaseDate);
|
||||
PaperCard getCardFromEditionsReleasedAfter(String cardName, CardArtPreference artPreference, int artIndex, Date releaseDate, Predicate<PaperCard> filter);
|
||||
|
||||
|
||||
|
||||
/* CARDS COLLECTION RETRIEVAL METHODS
|
||||
* ================================== */
|
||||
Collection<PaperCard> getAllCards();
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
package forge.card;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import forge.deck.DeckRecognizer;
|
||||
|
||||
import forge.util.ITranslatable;
|
||||
import forge.util.Localizer;
|
||||
|
||||
/**
|
||||
* Holds byte values for each color magic has.
|
||||
@@ -157,21 +159,24 @@ public final class MagicColor {
|
||||
}
|
||||
}
|
||||
|
||||
public enum Color {
|
||||
WHITE(Constant.WHITE, MagicColor.WHITE, "{W}"),
|
||||
BLUE(Constant.BLUE, MagicColor.BLUE, "{U}"),
|
||||
BLACK(Constant.BLACK, MagicColor.BLACK, "{B}"),
|
||||
RED(Constant.RED, MagicColor.RED, "{R}"),
|
||||
GREEN(Constant.GREEN, MagicColor.GREEN, "{G}"),
|
||||
COLORLESS(Constant.COLORLESS, MagicColor.COLORLESS, "{C}");
|
||||
public enum Color implements ITranslatable {
|
||||
WHITE(Constant.WHITE, MagicColor.WHITE, "W", "lblWhite"),
|
||||
BLUE(Constant.BLUE, MagicColor.BLUE, "U", "lblBlue"),
|
||||
BLACK(Constant.BLACK, MagicColor.BLACK, "B", "lblBlack"),
|
||||
RED(Constant.RED, MagicColor.RED, "R", "lblRed"),
|
||||
GREEN(Constant.GREEN, MagicColor.GREEN, "G", "lblGreen"),
|
||||
COLORLESS(Constant.COLORLESS, MagicColor.COLORLESS, "C", "lblColorless");
|
||||
|
||||
private final String name, symbol;
|
||||
private final String name, shortName, symbol;
|
||||
private final String label;
|
||||
private final byte colormask;
|
||||
|
||||
Color(String name0, byte colormask0, String symbol0) {
|
||||
Color(String name0, byte colormask0, String shortName, String label) {
|
||||
name = name0;
|
||||
colormask = colormask0;
|
||||
symbol = symbol0;
|
||||
this.shortName = shortName;
|
||||
symbol = "{" + shortName + "}";
|
||||
this.label = label;
|
||||
}
|
||||
|
||||
public static Color fromByte(final byte color) {
|
||||
@@ -185,25 +190,25 @@ public final class MagicColor {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public String getLocalizedName() {
|
||||
//Should probably move some of this logic back here, or at least to a more general location.
|
||||
return DeckRecognizer.getLocalisedMagicColorName(getName());
|
||||
public String getShortName() {
|
||||
return shortName;
|
||||
}
|
||||
|
||||
public byte getColormask() {
|
||||
@Override
|
||||
public String getTranslatedName() {
|
||||
return Localizer.getInstance().getMessage(label);
|
||||
}
|
||||
|
||||
public byte getColorMask() {
|
||||
return colormask;
|
||||
}
|
||||
public String getSymbol() {
|
||||
return symbol;
|
||||
}
|
||||
@Override
|
||||
public String toString() {
|
||||
return name;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
*/
|
||||
package forge.card.mana;
|
||||
|
||||
import forge.card.ColorSet;
|
||||
import forge.util.BinaryUtil;
|
||||
|
||||
/**
|
||||
@@ -34,52 +35,51 @@ public enum ManaCostShard {
|
||||
COLORLESS(ManaAtom.COLORLESS, "C"),
|
||||
|
||||
/* Hybrid */
|
||||
WU(ManaAtom.WHITE | ManaAtom.BLUE, "W/U", "WU"),
|
||||
WB(ManaAtom.WHITE | ManaAtom.BLACK, "W/B", "WB"),
|
||||
UB(ManaAtom.BLUE | ManaAtom.BLACK, "U/B", "UB"),
|
||||
UR(ManaAtom.BLUE | ManaAtom.RED, "U/R", "UR"),
|
||||
BR(ManaAtom.BLACK | ManaAtom.RED, "B/R", "BR"),
|
||||
BG(ManaAtom.BLACK | ManaAtom.GREEN, "B/G", "BG"),
|
||||
RW(ManaAtom.RED | ManaAtom.WHITE, "R/W", "RW"),
|
||||
RG(ManaAtom.RED | ManaAtom.GREEN, "R/G", "RG"),
|
||||
GW(ManaAtom.GREEN | ManaAtom.WHITE, "G/W", "GW"),
|
||||
GU(ManaAtom.GREEN | ManaAtom.BLUE, "G/U", "GU"),
|
||||
WU(ManaAtom.WHITE | ManaAtom.BLUE, "W/U"),
|
||||
WB(ManaAtom.WHITE | ManaAtom.BLACK, "W/B"),
|
||||
UB(ManaAtom.BLUE | ManaAtom.BLACK, "U/B"),
|
||||
UR(ManaAtom.BLUE | ManaAtom.RED, "U/R"),
|
||||
BR(ManaAtom.BLACK | ManaAtom.RED, "B/R"),
|
||||
BG(ManaAtom.BLACK | ManaAtom.GREEN, "B/G"),
|
||||
RW(ManaAtom.RED | ManaAtom.WHITE, "R/W"),
|
||||
RG(ManaAtom.RED | ManaAtom.GREEN, "R/G"),
|
||||
GW(ManaAtom.GREEN | ManaAtom.WHITE, "G/W"),
|
||||
GU(ManaAtom.GREEN | ManaAtom.BLUE, "G/U"),
|
||||
|
||||
/* Or 2 generic */
|
||||
W2(ManaAtom.WHITE | ManaAtom.OR_2_GENERIC, "2/W", "2W"),
|
||||
U2(ManaAtom.BLUE | ManaAtom.OR_2_GENERIC, "2/U", "2U"),
|
||||
B2(ManaAtom.BLACK | ManaAtom.OR_2_GENERIC, "2/B", "2B"),
|
||||
R2(ManaAtom.RED | ManaAtom.OR_2_GENERIC, "2/R", "2R"),
|
||||
G2(ManaAtom.GREEN | ManaAtom.OR_2_GENERIC, "2/G", "2G"),
|
||||
W2(ManaAtom.WHITE | ManaAtom.OR_2_GENERIC, "2/W"),
|
||||
U2(ManaAtom.BLUE | ManaAtom.OR_2_GENERIC, "2/U"),
|
||||
B2(ManaAtom.BLACK | ManaAtom.OR_2_GENERIC, "2/B"),
|
||||
R2(ManaAtom.RED | ManaAtom.OR_2_GENERIC, "2/R"),
|
||||
G2(ManaAtom.GREEN | ManaAtom.OR_2_GENERIC, "2/G"),
|
||||
|
||||
/* Or Colorless */
|
||||
CW(ManaAtom.WHITE | ManaAtom.COLORLESS, "C/W", "CW"),
|
||||
CU(ManaAtom.BLUE | ManaAtom.COLORLESS, "C/U", "CU"),
|
||||
CB(ManaAtom.BLACK | ManaAtom.COLORLESS, "C/B", "CB"),
|
||||
CR(ManaAtom.RED | ManaAtom.COLORLESS, "C/R", "CR"),
|
||||
CG(ManaAtom.GREEN | ManaAtom.COLORLESS, "C/G", "CG"),
|
||||
CW(ManaAtom.WHITE | ManaAtom.COLORLESS, "C/W"),
|
||||
CU(ManaAtom.BLUE | ManaAtom.COLORLESS, "C/U"),
|
||||
CB(ManaAtom.BLACK | ManaAtom.COLORLESS, "C/B"),
|
||||
CR(ManaAtom.RED | ManaAtom.COLORLESS, "C/R"),
|
||||
CG(ManaAtom.GREEN | ManaAtom.COLORLESS, "C/G"),
|
||||
|
||||
// Snow and colorless
|
||||
S(ManaAtom.IS_SNOW, "S"),
|
||||
GENERIC(ManaAtom.GENERIC, "1"),
|
||||
|
||||
|
||||
/* Phyrexian */
|
||||
WP(ManaAtom.WHITE | ManaAtom.OR_2_LIFE, "W/P", "WP"),
|
||||
UP(ManaAtom.BLUE | ManaAtom.OR_2_LIFE, "U/P", "UP"),
|
||||
BP(ManaAtom.BLACK | ManaAtom.OR_2_LIFE, "B/P", "BP"),
|
||||
RP(ManaAtom.RED | ManaAtom.OR_2_LIFE, "R/P", "RP"),
|
||||
GP(ManaAtom.GREEN | ManaAtom.OR_2_LIFE, "G/P", "GP"),
|
||||
BGP(ManaAtom.BLACK | ManaAtom.GREEN | ManaAtom.OR_2_LIFE, "B/G/P", "BGP"),
|
||||
BRP(ManaAtom.BLACK | ManaAtom.RED | ManaAtom.OR_2_LIFE, "B/R/P", "BRP"),
|
||||
GUP(ManaAtom.GREEN | ManaAtom.BLUE | ManaAtom.OR_2_LIFE, "G/U/P", "GUP"),
|
||||
GWP(ManaAtom.GREEN | ManaAtom.WHITE | ManaAtom.OR_2_LIFE, "G/W/P", "GWP"),
|
||||
RGP(ManaAtom.RED | ManaAtom.GREEN | ManaAtom.OR_2_LIFE, "R/G/P", "RGP"),
|
||||
RWP(ManaAtom.RED | ManaAtom.WHITE | ManaAtom.OR_2_LIFE, "R/W/P", "RWP"),
|
||||
UBP(ManaAtom.BLUE | ManaAtom.BLACK | ManaAtom.OR_2_LIFE, "U/B/P", "UBP"),
|
||||
URP(ManaAtom.BLUE | ManaAtom.RED | ManaAtom.OR_2_LIFE, "U/R/P", "URP"),
|
||||
WBP(ManaAtom.WHITE | ManaAtom.BLACK | ManaAtom.OR_2_LIFE, "W/B/P", "WBP"),
|
||||
WUP(ManaAtom.WHITE | ManaAtom.BLUE | ManaAtom.OR_2_LIFE, "W/U/P", "WUP"),
|
||||
WP(ManaAtom.WHITE | ManaAtom.OR_2_LIFE, "W/P"),
|
||||
UP(ManaAtom.BLUE | ManaAtom.OR_2_LIFE, "U/P"),
|
||||
BP(ManaAtom.BLACK | ManaAtom.OR_2_LIFE, "B/P"),
|
||||
RP(ManaAtom.RED | ManaAtom.OR_2_LIFE, "R/P"),
|
||||
GP(ManaAtom.GREEN | ManaAtom.OR_2_LIFE, "G/P"),
|
||||
BGP(ManaAtom.BLACK | ManaAtom.GREEN | ManaAtom.OR_2_LIFE, "B/G/P"),
|
||||
BRP(ManaAtom.BLACK | ManaAtom.RED | ManaAtom.OR_2_LIFE, "B/R/P"),
|
||||
GUP(ManaAtom.GREEN | ManaAtom.BLUE | ManaAtom.OR_2_LIFE, "G/U/P"),
|
||||
GWP(ManaAtom.GREEN | ManaAtom.WHITE | ManaAtom.OR_2_LIFE, "G/W/P"),
|
||||
RGP(ManaAtom.RED | ManaAtom.GREEN | ManaAtom.OR_2_LIFE, "R/G/P"),
|
||||
RWP(ManaAtom.RED | ManaAtom.WHITE | ManaAtom.OR_2_LIFE, "R/W/P"),
|
||||
UBP(ManaAtom.BLUE | ManaAtom.BLACK | ManaAtom.OR_2_LIFE, "U/B/P"),
|
||||
URP(ManaAtom.BLUE | ManaAtom.RED | ManaAtom.OR_2_LIFE, "U/R/P"),
|
||||
WBP(ManaAtom.WHITE | ManaAtom.BLACK | ManaAtom.OR_2_LIFE, "W/B/P"),
|
||||
WUP(ManaAtom.WHITE | ManaAtom.BLUE | ManaAtom.OR_2_LIFE, "W/U/P"),
|
||||
|
||||
X(ManaAtom.IS_X, "X"),
|
||||
|
||||
@@ -108,26 +108,12 @@ public enum ManaCostShard {
|
||||
* the s value
|
||||
*/
|
||||
ManaCostShard(final int value, final String sValue) {
|
||||
this(value, sValue, sValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiates a new card mana cost shard.
|
||||
*
|
||||
* @param value
|
||||
* the value
|
||||
* @param sValue
|
||||
* the s value
|
||||
* @param imgKey
|
||||
* the img key
|
||||
*/
|
||||
ManaCostShard(final int value, final String sValue, final String imgKey) {
|
||||
this.shard = value;
|
||||
this.cmc = this.getCMC();
|
||||
this.cmpc = this.getCmpCost();
|
||||
this.stringValue = "{" + sValue + "}";
|
||||
this.shortStringValue = sValue;
|
||||
this.imageKey = imgKey;
|
||||
this.imageKey = sValue.replace("/", "");
|
||||
}
|
||||
|
||||
public static final int COLORS_SUPERPOSITION = ManaAtom.WHITE | ManaAtom.BLUE | ManaAtom.BLACK | ManaAtom.RED | ManaAtom.GREEN;
|
||||
@@ -186,6 +172,10 @@ public enum ManaCostShard {
|
||||
return (byte)(this.shard & COLORS_SUPERPOSITION);
|
||||
}
|
||||
|
||||
public final ColorSet getColor() {
|
||||
return ColorSet.fromMask(getColorMask());
|
||||
}
|
||||
|
||||
/**
|
||||
* Value of.
|
||||
*
|
||||
|
||||
@@ -115,6 +115,20 @@ public class Deck extends DeckBase implements Iterable<Entry<DeckSection, CardPo
|
||||
return parts.get(DeckSection.Main);
|
||||
}
|
||||
|
||||
public Pair<Deck, List<PaperCard>> getValid() {
|
||||
List<PaperCard> unsupported = new ArrayList<>();
|
||||
for (Entry<DeckSection, CardPool> kv : parts.entrySet()) {
|
||||
CardPool pool = kv.getValue();
|
||||
for (Entry<PaperCard, Integer> pc : pool) {
|
||||
if (pc.getKey().getRules() != null && pc.getKey().getRules().isUnsupported()) {
|
||||
unsupported.add(pc.getKey());
|
||||
pool.remove(pc.getKey());
|
||||
}
|
||||
}
|
||||
}
|
||||
return Pair.of(this, unsupported);
|
||||
}
|
||||
|
||||
public List<PaperCard> getCommanders() {
|
||||
List<PaperCard> result = Lists.newArrayList();
|
||||
final CardPool cp = get(DeckSection.Commander);
|
||||
|
||||
@@ -22,6 +22,7 @@ import forge.StaticData;
|
||||
import forge.card.CardDb;
|
||||
import forge.card.CardEdition;
|
||||
import forge.card.CardType;
|
||||
import forge.card.ColorSet;
|
||||
import forge.card.MagicColor;
|
||||
import forge.item.IPaperCard;
|
||||
import forge.item.PaperCard;
|
||||
@@ -49,6 +50,16 @@ public class DeckRecognizer {
|
||||
LIMITED_CARD,
|
||||
CARD_FROM_NOT_ALLOWED_SET,
|
||||
CARD_FROM_INVALID_SET,
|
||||
/**
|
||||
* Valid card request, but can't be imported because the player does not have enough copies.
|
||||
* Should be replaced with a different printing if possible.
|
||||
*/
|
||||
CARD_NOT_IN_INVENTORY,
|
||||
/**
|
||||
* Valid card request for a card that isn't in the player's inventory, but new copies can be acquired freely.
|
||||
* Usually used for basic lands. Should be supplied to the import controller by the editor.
|
||||
*/
|
||||
FREE_CARD_NOT_IN_INVENTORY,
|
||||
// Warning messages
|
||||
WARNING_MESSAGE,
|
||||
UNKNOWN_CARD,
|
||||
@@ -63,10 +74,14 @@ public class DeckRecognizer {
|
||||
CARD_TYPE,
|
||||
CARD_RARITY,
|
||||
CARD_CMC,
|
||||
MANA_COLOUR
|
||||
MANA_COLOUR;
|
||||
|
||||
public static final EnumSet<TokenType> CARD_TOKEN_TYPES = EnumSet.of(LEGAL_CARD, LIMITED_CARD, CARD_FROM_NOT_ALLOWED_SET, CARD_FROM_INVALID_SET, CARD_NOT_IN_INVENTORY, FREE_CARD_NOT_IN_INVENTORY);
|
||||
public static final EnumSet<TokenType> IN_DECK_TOKEN_TYPES = EnumSet.of(LEGAL_CARD, LIMITED_CARD, DECK_NAME, FREE_CARD_NOT_IN_INVENTORY);
|
||||
public static final EnumSet<TokenType> CARD_PLACEHOLDER_TOKEN_TYPES = EnumSet.of(CARD_TYPE, CARD_RARITY, CARD_CMC, MANA_COLOUR);
|
||||
}
|
||||
|
||||
public enum LimitedCardType{
|
||||
public enum LimitedCardType {
|
||||
BANNED,
|
||||
RESTRICTED,
|
||||
}
|
||||
@@ -108,6 +123,10 @@ public class DeckRecognizer {
|
||||
return new Token(TokenType.CARD_FROM_INVALID_SET, count, card, cardRequestHasSetCode);
|
||||
}
|
||||
|
||||
public static Token NotInInventoryFree(final PaperCard card, final int count, final DeckSection section) {
|
||||
return new Token(TokenType.FREE_CARD_NOT_IN_INVENTORY, count, card, section, true);
|
||||
}
|
||||
|
||||
// WARNING MESSAGES
|
||||
// ================
|
||||
public static Token UnknownCard(final String cardName, final String setCode, final int count) {
|
||||
@@ -126,6 +145,10 @@ public class DeckRecognizer {
|
||||
return new Token(TokenType.WARNING_MESSAGE, msg);
|
||||
}
|
||||
|
||||
public static Token NotInInventory(final PaperCard card, final int count, final DeckSection section) {
|
||||
return new Token(TokenType.CARD_NOT_IN_INVENTORY, count, card, section, false);
|
||||
}
|
||||
|
||||
/* =================================
|
||||
* DECK SECTIONS
|
||||
* ================================= */
|
||||
@@ -239,14 +262,11 @@ public class DeckRecognizer {
|
||||
/**
|
||||
* Filters all token types that have a PaperCard instance set (not null)
|
||||
* @return true for tokens of type:
|
||||
* LEGAL_CARD, LIMITED_CARD, CARD_FROM_NOT_ALLOWED_SET and CARD_FROM_INVALID_SET.
|
||||
* LEGAL_CARD, LIMITED_CARD, CARD_FROM_NOT_ALLOWED_SET and CARD_FROM_INVALID_SET, CARD_NOT_IN_INVENTORY, FREE_CARD_NOT_IN_INVENTORY.
|
||||
* False otherwise.
|
||||
*/
|
||||
public boolean isCardToken() {
|
||||
return (this.type == TokenType.LEGAL_CARD ||
|
||||
this.type == TokenType.LIMITED_CARD ||
|
||||
this.type == TokenType.CARD_FROM_NOT_ALLOWED_SET ||
|
||||
this.type == TokenType.CARD_FROM_INVALID_SET);
|
||||
return TokenType.CARD_TOKEN_TYPES.contains(this.type);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -255,9 +275,7 @@ public class DeckRecognizer {
|
||||
* LEGAL_CARD, LIMITED_CARD, DECK_NAME; false otherwise.
|
||||
*/
|
||||
public boolean isTokenForDeck() {
|
||||
return (this.type == TokenType.LEGAL_CARD ||
|
||||
this.type == TokenType.LIMITED_CARD ||
|
||||
this.type == TokenType.DECK_NAME);
|
||||
return TokenType.IN_DECK_TOKEN_TYPES.contains(this.type);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -266,7 +284,7 @@ public class DeckRecognizer {
|
||||
* False otherwise.
|
||||
*/
|
||||
public boolean isCardTokenForDeck() {
|
||||
return (this.type == TokenType.LEGAL_CARD || this.type == TokenType.LIMITED_CARD);
|
||||
return isCardToken() && isTokenForDeck();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -276,10 +294,7 @@ public class DeckRecognizer {
|
||||
* CARD_RARITY, CARD_CMC, CARD_TYPE, MANA_COLOUR
|
||||
*/
|
||||
public boolean isCardPlaceholder(){
|
||||
return (this.type == TokenType.CARD_RARITY ||
|
||||
this.type == TokenType.CARD_CMC ||
|
||||
this.type == TokenType.MANA_COLOUR ||
|
||||
this.type == TokenType.CARD_TYPE);
|
||||
return TokenType.CARD_PLACEHOLDER_TOKEN_TYPES.contains(this.type);
|
||||
}
|
||||
|
||||
/** Determines if current token is a Deck Section token
|
||||
@@ -536,7 +551,7 @@ public class DeckRecognizer {
|
||||
PaperCard tokenCard = token.getCard();
|
||||
|
||||
if (isAllowed(tokenSection)) {
|
||||
if (!tokenSection.equals(referenceDeckSectionInParsing)) {
|
||||
if (tokenSection != referenceDeckSectionInParsing) {
|
||||
Token sectionToken = Token.DeckSection(tokenSection.name(), this.allowedDeckSections);
|
||||
// just check that last token is stack is a card placeholder.
|
||||
// In that case, add the new section token before the placeholder
|
||||
@@ -575,7 +590,7 @@ public class DeckRecognizer {
|
||||
refLine = purgeAllLinks(refLine);
|
||||
|
||||
String line;
|
||||
if (StringUtils.startsWith(refLine, LINE_COMMENT_DELIMITER_OR_MD_HEADER))
|
||||
if (refLine.startsWith(LINE_COMMENT_DELIMITER_OR_MD_HEADER))
|
||||
line = refLine.replaceAll(LINE_COMMENT_DELIMITER_OR_MD_HEADER, "");
|
||||
else
|
||||
line = refLine.trim(); // Remove any trailing formatting
|
||||
@@ -584,7 +599,7 @@ public class DeckRecognizer {
|
||||
// Final fantasy cards like Summon: Choco/Mog should be ommited to be recognized. TODO: fix maybe for future cards
|
||||
if (!line.contains("Summon:"))
|
||||
line = SEARCH_SINGLE_SLASH.matcher(line).replaceFirst(" // ");
|
||||
if (StringUtils.startsWith(line, ASTERISK)) // markdown lists (tappedout md export)
|
||||
if (line.startsWith(ASTERISK)) // Markdown lists (tappedout md export)
|
||||
line = line.substring(2);
|
||||
|
||||
// == Patches to Corner Cases
|
||||
@@ -600,8 +615,8 @@ public class DeckRecognizer {
|
||||
Token result = recogniseCardToken(line, referenceSection);
|
||||
if (result == null)
|
||||
result = recogniseNonCardToken(line);
|
||||
return result != null ? result : StringUtils.startsWith(refLine, DOUBLE_SLASH) ||
|
||||
StringUtils.startsWith(refLine, LINE_COMMENT_DELIMITER_OR_MD_HEADER) ?
|
||||
return result != null ? result : refLine.startsWith(DOUBLE_SLASH) ||
|
||||
refLine.startsWith(LINE_COMMENT_DELIMITER_OR_MD_HEADER) ?
|
||||
new Token(TokenType.COMMENT, 0, refLine) : new Token(TokenType.UNKNOWN_TEXT, 0, refLine);
|
||||
}
|
||||
|
||||
@@ -613,7 +628,7 @@ public class DeckRecognizer {
|
||||
while (m.find()) {
|
||||
line = line.replaceAll(m.group(), "").trim();
|
||||
}
|
||||
if (StringUtils.endsWith(line, "()"))
|
||||
if (line.endsWith("()"))
|
||||
return line.substring(0, line.length()-2);
|
||||
return line;
|
||||
}
|
||||
@@ -741,21 +756,12 @@ public class DeckRecognizer {
|
||||
// This would save tons of time in parsing Input + would also allow to return UnsupportedCardTokens beforehand
|
||||
private DeckSection getTokenSection(String deckSec, DeckSection currentDeckSection, PaperCard card){
|
||||
if (deckSec != null) {
|
||||
DeckSection cardSection;
|
||||
switch (deckSec.toUpperCase().trim()) {
|
||||
case "MB":
|
||||
cardSection = DeckSection.Main;
|
||||
break;
|
||||
case "SB":
|
||||
cardSection = DeckSection.Sideboard;
|
||||
break;
|
||||
case "CM":
|
||||
cardSection = DeckSection.Commander;
|
||||
break;
|
||||
default:
|
||||
cardSection = DeckSection.matchingSection(card);
|
||||
break;
|
||||
}
|
||||
DeckSection cardSection = switch (deckSec.toUpperCase().trim()) {
|
||||
case "MB" -> DeckSection.Main;
|
||||
case "SB" -> DeckSection.Sideboard;
|
||||
case "CM" -> DeckSection.Commander;
|
||||
default -> DeckSection.matchingSection(card);
|
||||
};
|
||||
if (cardSection.validate(card))
|
||||
return cardSection;
|
||||
}
|
||||
@@ -988,80 +994,37 @@ public class DeckRecognizer {
|
||||
|
||||
private static String getMagicColourLabel(MagicColor.Color magicColor) {
|
||||
if (magicColor == null) // Multicolour
|
||||
return String.format("%s {W}{U}{B}{R}{G}", getLocalisedMagicColorName("Multicolour"));
|
||||
return String.format("%s %s", magicColor.getLocalizedName(), magicColor.getSymbol());
|
||||
return String.format("%s {W}{U}{B}{R}{G}", Localizer.getInstance().getMessage("lblMulticolor"));
|
||||
return String.format("%s %s", magicColor.getTranslatedName(), magicColor.getSymbol());
|
||||
}
|
||||
|
||||
private static final HashMap<Integer, String> manaSymbolsMap = new HashMap<Integer, String>() {{
|
||||
put(MagicColor.WHITE | MagicColor.BLUE, "WU");
|
||||
put(MagicColor.BLUE | MagicColor.BLACK, "UB");
|
||||
put(MagicColor.BLACK | MagicColor.RED, "BR");
|
||||
put(MagicColor.RED | MagicColor.GREEN, "RG");
|
||||
put(MagicColor.GREEN | MagicColor.WHITE, "GW");
|
||||
put(MagicColor.WHITE | MagicColor.BLACK, "WB");
|
||||
put(MagicColor.BLUE | MagicColor.RED, "UR");
|
||||
put(MagicColor.BLACK | MagicColor.GREEN, "BG");
|
||||
put(MagicColor.RED | MagicColor.WHITE, "RW");
|
||||
put(MagicColor.GREEN | MagicColor.BLUE, "GU");
|
||||
}};
|
||||
private static String getMagicColourLabel(MagicColor.Color magicColor1, MagicColor.Color magicColor2){
|
||||
private static String getMagicColourLabel(MagicColor.Color magicColor1, MagicColor.Color magicColor2) {
|
||||
if (magicColor2 == null || magicColor2 == MagicColor.Color.COLORLESS
|
||||
|| magicColor1 == MagicColor.Color.COLORLESS)
|
||||
return String.format("%s // %s", getMagicColourLabel(magicColor1), getMagicColourLabel(magicColor2));
|
||||
String localisedName1 = magicColor1.getLocalizedName();
|
||||
String localisedName2 = magicColor2.getLocalizedName();
|
||||
String comboManaSymbol = manaSymbolsMap.get(magicColor1.getColormask() | magicColor2.getColormask());
|
||||
return String.format("%s/%s {%s}", localisedName1, localisedName2, comboManaSymbol);
|
||||
String localisedName1 = magicColor1.getTranslatedName();
|
||||
String localisedName2 = magicColor2.getTranslatedName();
|
||||
return String.format("%s/%s {%s}", localisedName1, localisedName2, ColorSet.fromEnums(magicColor1, magicColor2));
|
||||
}
|
||||
|
||||
private static MagicColor.Color getMagicColor(String colorName){
|
||||
if (colorName.toLowerCase().startsWith("multi") || colorName.equalsIgnoreCase("m"))
|
||||
return null; // will be handled separately
|
||||
|
||||
byte color = MagicColor.fromName(colorName.toLowerCase());
|
||||
switch (color) {
|
||||
case MagicColor.WHITE:
|
||||
return MagicColor.Color.WHITE;
|
||||
case MagicColor.BLUE:
|
||||
return MagicColor.Color.BLUE;
|
||||
case MagicColor.BLACK:
|
||||
return MagicColor.Color.BLACK;
|
||||
case MagicColor.RED:
|
||||
return MagicColor.Color.RED;
|
||||
case MagicColor.GREEN:
|
||||
return MagicColor.Color.GREEN;
|
||||
default:
|
||||
return MagicColor.Color.COLORLESS;
|
||||
|
||||
}
|
||||
return MagicColor.Color.fromByte(MagicColor.fromName(colorName.toLowerCase()));
|
||||
}
|
||||
|
||||
public static String getLocalisedMagicColorName(String colorName){
|
||||
Localizer localizer = Localizer.getInstance();
|
||||
switch(colorName.toLowerCase()){
|
||||
case MagicColor.Constant.WHITE:
|
||||
return localizer.getMessage("lblWhite");
|
||||
|
||||
case MagicColor.Constant.BLUE:
|
||||
return localizer.getMessage("lblBlue");
|
||||
|
||||
case MagicColor.Constant.BLACK:
|
||||
return localizer.getMessage("lblBlack");
|
||||
|
||||
case MagicColor.Constant.RED:
|
||||
return localizer.getMessage("lblRed");
|
||||
|
||||
case MagicColor.Constant.GREEN:
|
||||
return localizer.getMessage("lblGreen");
|
||||
|
||||
case MagicColor.Constant.COLORLESS:
|
||||
return localizer.getMessage("lblColorless");
|
||||
case "multicolour":
|
||||
case "multicolor":
|
||||
return localizer.getMessage("lblMulticolor");
|
||||
default:
|
||||
return "";
|
||||
}
|
||||
return switch (colorName.toLowerCase()) {
|
||||
case MagicColor.Constant.WHITE -> localizer.getMessage("lblWhite");
|
||||
case MagicColor.Constant.BLUE -> localizer.getMessage("lblBlue");
|
||||
case MagicColor.Constant.BLACK -> localizer.getMessage("lblBlack");
|
||||
case MagicColor.Constant.RED -> localizer.getMessage("lblRed");
|
||||
case MagicColor.Constant.GREEN -> localizer.getMessage("lblGreen");
|
||||
case MagicColor.Constant.COLORLESS -> localizer.getMessage("lblColorless");
|
||||
case "multicolour", "multicolor" -> localizer.getMessage("lblMulticolor");
|
||||
default -> "";
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1080,37 +1043,6 @@ public class DeckRecognizer {
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
|
||||
private static Pair<String, String> getManaNameAndSymbol(String matchedMana) {
|
||||
if (matchedMana == null)
|
||||
return null;
|
||||
|
||||
Localizer localizer = Localizer.getInstance();
|
||||
switch (matchedMana.toLowerCase()) {
|
||||
case MagicColor.Constant.WHITE:
|
||||
case "w":
|
||||
return Pair.of(localizer.getMessage("lblWhite"), MagicColor.Color.WHITE.getSymbol());
|
||||
case MagicColor.Constant.BLUE:
|
||||
case "u":
|
||||
return Pair.of(localizer.getMessage("lblBlue"), MagicColor.Color.BLUE.getSymbol());
|
||||
case MagicColor.Constant.BLACK:
|
||||
case "b":
|
||||
return Pair.of(localizer.getMessage("lblBlack"), MagicColor.Color.BLACK.getSymbol());
|
||||
case MagicColor.Constant.RED:
|
||||
case "r":
|
||||
return Pair.of(localizer.getMessage("lblRed"), MagicColor.Color.RED.getSymbol());
|
||||
case MagicColor.Constant.GREEN:
|
||||
case "g":
|
||||
return Pair.of(localizer.getMessage("lblGreen"), MagicColor.Color.GREEN.getSymbol());
|
||||
case MagicColor.Constant.COLORLESS:
|
||||
case "c":
|
||||
return Pair.of(localizer.getMessage("lblColorless"), MagicColor.Color.COLORLESS.getSymbol());
|
||||
default: // Multicolour
|
||||
return Pair.of(localizer.getMessage("lblMulticolor"), "");
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean isDeckName(final String lineAsIs) {
|
||||
if (lineAsIs == null)
|
||||
return false;
|
||||
|
||||
@@ -52,9 +52,4 @@ public interface IPaperCard extends InventoryItem, Serializable {
|
||||
default String getUntranslatedType() {
|
||||
return getRules().getType().toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
default String getUntranslatedOracle() {
|
||||
return getRules().getOracleText();
|
||||
}
|
||||
}
|
||||
@@ -375,7 +375,8 @@ public class PaperCard implements Comparable<IPaperCard>, InventoryItemFromSet,
|
||||
System.out.println("PaperCard: " + name + " not found with set and index " + edition + ", " + artIndex);
|
||||
pc = readObjectAlternate(name, edition);
|
||||
if (pc == null) {
|
||||
throw new IOException(TextUtil.concatWithSpace("Card", name, "not found with set and index", edition, Integer.toString(artIndex)));
|
||||
pc = StaticData.instance().getCommonCards().createUnsupportedCard(name);
|
||||
//throw new IOException(TextUtil.concatWithSpace("Card", name, "not found with set and index", edition, Integer.toString(artIndex)));
|
||||
}
|
||||
System.out.println("Alternate object found: " + pc.getName() + ", " + pc.getEdition() + ", " + pc.getArtIndex());
|
||||
}
|
||||
@@ -592,7 +593,7 @@ public class PaperCard implements Comparable<IPaperCard>, InventoryItemFromSet,
|
||||
|
||||
public PaperCardFlags withMarkedColors(ColorSet markedColors) {
|
||||
if(markedColors == null)
|
||||
markedColors = ColorSet.getNullColor();
|
||||
markedColors = ColorSet.C;
|
||||
return new PaperCardFlags(this, markedColors, null);
|
||||
}
|
||||
|
||||
|
||||
@@ -57,6 +57,42 @@ public abstract class PaperCardPredicates {
|
||||
return new PredicateFoil(isFoil);
|
||||
}
|
||||
|
||||
/**
|
||||
* Filters cards that were printed in any of the specified editions.
|
||||
*/
|
||||
public static Predicate<PaperCard> printedInAnyEditions(final String[] editionCodes) {
|
||||
Set<String> editions = new HashSet<>(Arrays.asList(editionCodes));
|
||||
|
||||
return card -> StaticData.instance().getCommonCards().getAllCards(card.getName()).stream()
|
||||
.map(PaperCard::getEdition).anyMatch(editionCode ->
|
||||
editions.contains(editionCode) &&
|
||||
StaticData.instance().getCardEdition(editionCode).isCardObtainable(card.getName())
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Filters cards that only printed in any of the specified editions.
|
||||
*/
|
||||
public static Predicate<PaperCard> onlyPrintedInEditions(final String[] editionCodes) {
|
||||
Set<String> editions = new HashSet<>(Arrays.asList(editionCodes));
|
||||
|
||||
return card -> StaticData.instance().getCommonCards().getAllCards(card.getName()).stream()
|
||||
.map(PaperCard::getEdition).allMatch(editionCode ->
|
||||
editions.contains(editionCode) &&
|
||||
StaticData.instance().getCardEdition(editionCode).isCardObtainable(card.getName())
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Filters cards that are obtainable in any edition.
|
||||
*/
|
||||
public static Predicate<PaperCard> isObtainableAnyEdition() {
|
||||
return card -> StaticData.instance().getCommonCards().getAllCards(card.getName()).stream()
|
||||
.map(PaperCard::getEdition).anyMatch(editionCode ->
|
||||
StaticData.instance().getCardEdition(editionCode).isCardObtainable(card.getName())
|
||||
);
|
||||
}
|
||||
|
||||
private static final class PredicatePrintedWithRarity implements Predicate<PaperCard> {
|
||||
private final CardRarity matchingRarity;
|
||||
|
||||
@@ -76,25 +112,19 @@ public abstract class PaperCardPredicates {
|
||||
}
|
||||
|
||||
private static final class PredicateColor implements Predicate<PaperCard> {
|
||||
private final byte operand;
|
||||
private final MagicColor.Color operand;
|
||||
|
||||
private PredicateColor(final byte color) {
|
||||
private PredicateColor(final MagicColor.Color color) {
|
||||
this.operand = color;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean test(final PaperCard card) {
|
||||
for (final byte color : card.getRules().getColor()) {
|
||||
if (color == operand) {
|
||||
return true;
|
||||
}
|
||||
if (card.getRules().getColor().hasAnyColor(operand)) {
|
||||
return true;
|
||||
}
|
||||
if (card.getRules().getType().hasType(CardType.CoreType.Land)) {
|
||||
for (final byte color : card.getRules().getColorIdentity()) {
|
||||
if (color == operand) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (card.getRules().getType().hasType(CardType.CoreType.Land) && card.getRules().getColorIdentity().hasAnyColor(operand)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -199,11 +229,11 @@ public abstract class PaperCardPredicates {
|
||||
public static final Predicate<PaperCard> IS_RARE_OR_MYTHIC = PaperCardPredicates.IS_RARE.or(PaperCardPredicates.IS_MYTHIC_RARE);
|
||||
public static final Predicate<PaperCard> IS_SPECIAL = new PredicateRarity(CardRarity.Special);
|
||||
public static final Predicate<PaperCard> IS_BASIC_LAND_RARITY = new PredicateRarity(CardRarity.BasicLand);
|
||||
public static final Predicate<PaperCard> IS_BLACK = new PredicateColor(MagicColor.BLACK);
|
||||
public static final Predicate<PaperCard> IS_BLUE = new PredicateColor(MagicColor.BLUE);
|
||||
public static final Predicate<PaperCard> IS_GREEN = new PredicateColor(MagicColor.GREEN);
|
||||
public static final Predicate<PaperCard> IS_RED = new PredicateColor(MagicColor.RED);
|
||||
public static final Predicate<PaperCard> IS_WHITE = new PredicateColor(MagicColor.WHITE);
|
||||
public static final Predicate<PaperCard> IS_BLACK = new PredicateColor(MagicColor.Color.BLACK);
|
||||
public static final Predicate<PaperCard> IS_BLUE = new PredicateColor(MagicColor.Color.BLUE);
|
||||
public static final Predicate<PaperCard> IS_GREEN = new PredicateColor(MagicColor.Color.GREEN);
|
||||
public static final Predicate<PaperCard> IS_RED = new PredicateColor(MagicColor.Color.RED);
|
||||
public static final Predicate<PaperCard> IS_WHITE = new PredicateColor(MagicColor.Color.WHITE);
|
||||
public static final Predicate<PaperCard> IS_COLORLESS = paperCard -> paperCard.getRules().getColor().isColorless();
|
||||
public static final Predicate<PaperCard> IS_UNREBALANCED = PaperCard::isUnRebalanced;
|
||||
public static final Predicate<PaperCard> IS_REBALANCED = PaperCard::isRebalanced;
|
||||
|
||||
@@ -156,7 +156,7 @@ public class PaperToken implements InventoryItemFromSet, IPaperCard {
|
||||
return false;
|
||||
CardSplitType cst = this.cardRules.getSplitType();
|
||||
//expand this on future for other tokens that has other backsides besides transform..
|
||||
return cst == CardSplitType.Transform;
|
||||
return cst == CardSplitType.Transform || cst == CardSplitType.Modal;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -633,7 +633,10 @@ public class BoosterGenerator {
|
||||
System.out.println("Parsing from main code: " + mainCode);
|
||||
String sheetName = StringUtils.strip(mainCode.substring(10), "()\" ");
|
||||
System.out.println("Attempting to lookup: " + sheetName);
|
||||
src = tryGetStaticSheet(sheetName).toFlatList();
|
||||
PrintSheet fromSheet = tryGetStaticSheet(sheetName);
|
||||
if (fromSheet == null)
|
||||
throw new RuntimeException("PrintSheet Error: " + ps.getName() + " didn't find " + sheetName + " from " + mainCode);
|
||||
src = fromSheet.toFlatList();
|
||||
setPred = x -> true;
|
||||
|
||||
} else if (mainCode.startsWith("promo") || mainCode.startsWith("name")) { // get exactly the named cards, that's a tiny inlined print sheet
|
||||
|
||||
@@ -10,13 +10,11 @@ public interface ITranslatable extends IHasName {
|
||||
default String getUntranslatedName() {
|
||||
return getName();
|
||||
}
|
||||
default String getTranslatedName() {
|
||||
return getName();
|
||||
}
|
||||
|
||||
default String getUntranslatedType() {
|
||||
return "";
|
||||
}
|
||||
|
||||
default String getUntranslatedOracle() {
|
||||
return "";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -207,8 +207,6 @@ public class ImageUtil {
|
||||
else
|
||||
editionCode = cp.getEdition().toLowerCase();
|
||||
String cardCollectorNumber = cp.getCollectorNumber();
|
||||
// Hack to account for variations in Arabian Nights
|
||||
cardCollectorNumber = cardCollectorNumber.replace("+", "†");
|
||||
// override old planechase sets from their modified id since scryfall move the planechase cards outside their original setcode
|
||||
if (cardCollectorNumber.startsWith("OHOP")) {
|
||||
editionCode = "ohop";
|
||||
@@ -252,6 +250,11 @@ public class ImageUtil {
|
||||
: "&face=front");
|
||||
}
|
||||
|
||||
if (cardCollectorNumber.endsWith("☇")) {
|
||||
faceParam = "&face=back";
|
||||
cardCollectorNumber = cardCollectorNumber.substring(0, cardCollectorNumber.length() - 1);
|
||||
}
|
||||
|
||||
return String.format("%s/%s/%s?format=image&version=%s%s", editionCode, encodeUtf8(cardCollectorNumber),
|
||||
langCode, versionParam, faceParam);
|
||||
}
|
||||
@@ -261,6 +264,10 @@ public class ImageUtil {
|
||||
if (!faceParam.isEmpty()) {
|
||||
faceParam = (faceParam.equals("back") ? "&face=back" : "&face=front");
|
||||
}
|
||||
if (collectorNumber.endsWith("☇")) {
|
||||
faceParam = "&face=back";
|
||||
collectorNumber = collectorNumber.substring(0, collectorNumber.length() - 1);
|
||||
}
|
||||
return String.format("%s/%s/%s?format=image&version=%s%s", setCode, encodeUtf8(collectorNumber),
|
||||
langCode, versionParam, faceParam);
|
||||
}
|
||||
@@ -281,8 +288,7 @@ public class ImageUtil {
|
||||
char c;
|
||||
for (int i = 0; i < in.length(); i++) {
|
||||
c = in.charAt(i);
|
||||
if ((c == '"') || (c == '/') || (c == ':') || (c == '?')) {
|
||||
} else {
|
||||
if ((c != '"') && (c != '/') && (c != ':') && (c != '?')) {
|
||||
out.append(c);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user