mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-16 18:58:00 +00:00
New lightweight classes for cards management in deck editors and quest mode (no other parts or project changed)
This commit is contained in:
16
.gitattributes
vendored
16
.gitattributes
vendored
@@ -9583,7 +9583,21 @@ src/main/java/forge/Time.java svneol=native#text/plain
|
||||
src/main/java/forge/UndoCommand.java svneol=native#text/plain
|
||||
src/main/java/forge/Upkeep.java svneol=native#text/plain
|
||||
src/main/java/forge/ZCTrigger.java svneol=native#text/plain
|
||||
src/main/java/forge/card/CardReference.java -text
|
||||
src/main/java/forge/card/CardColor.java -text
|
||||
src/main/java/forge/card/CardCoreType.java -text
|
||||
src/main/java/forge/card/CardDb.java -text
|
||||
src/main/java/forge/card/CardInSet.java -text
|
||||
src/main/java/forge/card/CardManaCost.java -text
|
||||
src/main/java/forge/card/CardManaCostShard.java -text
|
||||
src/main/java/forge/card/CardPool.java -text
|
||||
src/main/java/forge/card/CardPoolView.java -text
|
||||
src/main/java/forge/card/CardPrinted.java -text
|
||||
src/main/java/forge/card/CardRarity.java -text
|
||||
src/main/java/forge/card/CardRules.java -text
|
||||
src/main/java/forge/card/CardSet.java -text
|
||||
src/main/java/forge/card/CardSuperType.java -text
|
||||
src/main/java/forge/card/CardType.java -text
|
||||
src/main/java/forge/card/MtgDataParser.java -text
|
||||
src/main/java/forge/card/abilityFactory/AbilityFactory.java svneol=native#text/plain
|
||||
src/main/java/forge/card/abilityFactory/AbilityFactory_AlterLife.java svneol=native#text/plain
|
||||
src/main/java/forge/card/abilityFactory/AbilityFactory_Animate.java svneol=native#text/plain
|
||||
|
||||
66
src/main/java/forge/card/CardColor.java
Normal file
66
src/main/java/forge/card/CardColor.java
Normal file
@@ -0,0 +1,66 @@
|
||||
package forge.card;
|
||||
|
||||
import org.apache.tools.ant.taskdefs.Concat;
|
||||
|
||||
import forge.Constant;
|
||||
|
||||
/**
|
||||
* <p>CardColor class.</p>
|
||||
*
|
||||
* @author Forge
|
||||
* @version $Id: CardColor.java 9708 2011-08-09 19:34:12Z jendave $
|
||||
*/
|
||||
public final class CardColor implements Comparable<CardColor> {
|
||||
|
||||
public static final byte WHITE = 1 << 1;
|
||||
public static final byte BLUE = 1 << 2;
|
||||
public static final byte BLACK = 1 << 3;
|
||||
public static final byte RED = 1 << 4;
|
||||
public static final byte GREEN = 1 << 5;
|
||||
|
||||
private final byte myColor;
|
||||
|
||||
// TODO: some cards state "CardName is %color%" (e.g. pacts of...) - fix this later
|
||||
public CardColor(final CardManaCost mana) {
|
||||
myColor = mana.getColorProfile();
|
||||
}
|
||||
|
||||
public boolean hasAnyColor(final byte colormask) { return (myColor & colormask) != 0; }
|
||||
public boolean hasAllColors(final byte colormask) { return (myColor & colormask) == colormask; }
|
||||
|
||||
public int countColors() { byte v = myColor; int c = 0; for (; v != 0; c++) { v &= v - 1; } return c; } // bit count
|
||||
|
||||
public boolean isColorless() { return myColor == 0; }
|
||||
public boolean isMulticolor() { return countColors() > 1; }
|
||||
public boolean isMonoColor() { return countColors() == 1; }
|
||||
public boolean isEqual(final byte color) { return color == myColor; }
|
||||
|
||||
@Override
|
||||
public int compareTo(final CardColor other) { return myColor - other.myColor; }
|
||||
|
||||
// Presets
|
||||
public boolean hasWhite() { return hasAnyColor(WHITE); }
|
||||
public boolean hasBlue() { return hasAnyColor(BLUE); }
|
||||
public boolean hasBlack() { return hasAnyColor(BLACK); }
|
||||
public boolean hasRed() { return hasAnyColor(RED); }
|
||||
public boolean hasGreen() { return hasAnyColor(GREEN); }
|
||||
|
||||
public boolean isWhite() { return isEqual(WHITE); }
|
||||
public boolean isBlue() { return isEqual(BLUE); }
|
||||
public boolean isBlack() { return isEqual(BLACK); }
|
||||
public boolean isRed() { return isEqual(RED); }
|
||||
public boolean isGreen() { return isEqual(GREEN); }
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
switch (myColor) {
|
||||
case 0: return "";
|
||||
case WHITE: return "White"; // Constant.Color.White;
|
||||
case BLUE: return "Blue"; // Constant.Color.Blue;
|
||||
case BLACK: return "Black"; // Constant.Color.Black;
|
||||
case RED: return "Red"; // Constant.Color.Red;
|
||||
case GREEN: return "Green"; // Constant.Color.Green;
|
||||
default: return "Multi";
|
||||
}
|
||||
}
|
||||
}
|
||||
7
src/main/java/forge/card/CardCoreType.java
Normal file
7
src/main/java/forge/card/CardCoreType.java
Normal file
@@ -0,0 +1,7 @@
|
||||
package forge.card;
|
||||
|
||||
|
||||
public enum CardCoreType
|
||||
{
|
||||
Artifact, Creature, Enchantment, Instant, Land, Plane, Planeswalker, Scheme, Sorcery, Tribal, Vanguard
|
||||
}
|
||||
145
src/main/java/forge/card/CardDb.java
Normal file
145
src/main/java/forge/card/CardDb.java
Normal file
@@ -0,0 +1,145 @@
|
||||
package forge.card;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Hashtable;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.NoSuchElementException;
|
||||
import java.util.Properties;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import forge.Card;
|
||||
import forge.FileUtil;
|
||||
import forge.properties.ForgeProps;
|
||||
import forge.properties.NewConstants;
|
||||
|
||||
|
||||
/**
|
||||
* <p>CardOracleDatabase class.</p>
|
||||
*
|
||||
* @author Forge
|
||||
* @version $Id: CardOracleDatabase.java 9708 2011-08-09 19:34:12Z jendave $
|
||||
*/
|
||||
public final class CardDb {
|
||||
private static volatile CardDb onlyInstance = null; // 'volatile' keyword makes this working
|
||||
public static CardDb instance() {
|
||||
if (onlyInstance == null) {
|
||||
synchronized (CardDb.class) {
|
||||
if (onlyInstance == null) { // It's broken under 1.4 and below, on 1.5+ works again!
|
||||
onlyInstance = new CardDb();
|
||||
}
|
||||
}
|
||||
}
|
||||
return onlyInstance;
|
||||
}
|
||||
|
||||
// Here oracle cards
|
||||
private final Map<String, CardRules> cards = new Hashtable<String, CardRules>();
|
||||
// Here are refs, get them by name
|
||||
private final Map<String, CardPrinted> uniqueCards = new Hashtable<String, CardPrinted>();
|
||||
|
||||
// need this to obtain cardReference by name+set+artindex
|
||||
private final Map<String, Map<String, CardPrinted[]>> allCardsBySet = new Hashtable<String, Map<String, CardPrinted[]>>();
|
||||
// this is the same list in flat storage
|
||||
private final List<CardPrinted> allCardsFlat = new ArrayList<CardPrinted>();
|
||||
|
||||
|
||||
private CardDb() {
|
||||
List<String> mtgDataLines = FileUtil.readFile(ForgeProps.getFile(NewConstants.MTG_DATA));
|
||||
MtgDataParser parser = new MtgDataParser(mtgDataLines);
|
||||
while (parser.hasNext()) {
|
||||
addNewCard(parser.next());
|
||||
}
|
||||
}
|
||||
|
||||
public void addNewCard(final CardRules card) {
|
||||
if (null == card) { return; }
|
||||
//System.out.println(card.getName());
|
||||
String cardName = card.getName();
|
||||
|
||||
// 1. register among oracle uniques
|
||||
cards.put(cardName, card);
|
||||
|
||||
// 2. fill refs into two lists: one with
|
||||
CardPrinted lastAdded = null;
|
||||
for (Entry<String, CardInSet> s : card.getSetsPrinted()) {
|
||||
String set = s.getKey();
|
||||
|
||||
// get this set storage, if not found, create it!
|
||||
Map<String, CardPrinted[]> setMap = allCardsBySet.get(set);
|
||||
if (null == setMap) {
|
||||
setMap = new Hashtable<String, CardPrinted[]>();
|
||||
allCardsBySet.put(set, setMap);
|
||||
}
|
||||
|
||||
int count = s.getValue().getCopiesCount();
|
||||
CardPrinted[] cards = new CardPrinted[count];
|
||||
setMap.put(cardName, cards);
|
||||
for (int i = 0; i < count; i++) {
|
||||
lastAdded = CardPrinted.build(card, set, s.getValue().getRarity(), i+1);
|
||||
allCardsFlat.add(lastAdded);
|
||||
cards[i] = lastAdded;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
uniqueCards.put(cardName, lastAdded);
|
||||
}
|
||||
|
||||
// Single fetch
|
||||
public CardPrinted getCard(final String name) {
|
||||
// Sometimes they read from decks things like "CardName|Set" - but we can handle it
|
||||
int pipePos = name.indexOf('|');
|
||||
if (pipePos >= 0) { return getCard(name.substring(0, pipePos), name.substring(pipePos+1)); }
|
||||
// OK, plain name here
|
||||
CardPrinted card = uniqueCards.get(name);
|
||||
if (card != null) { return card; }
|
||||
throw new NoSuchElementException(String.format("Card '%s' not found in our database.", name));
|
||||
}
|
||||
// Advanced fetch by name+set
|
||||
public CardPrinted getCard(final String name, final String set) { return getCard(name, set, 1); }
|
||||
public CardPrinted getCard(final String name, final String set, final int artIndex) {
|
||||
// 1. get set
|
||||
Map<String, CardPrinted[]> cardsFromset = allCardsBySet.get(set);
|
||||
if (null == cardsFromset) {
|
||||
String err = String.format("Asked for card '%s' from set '%s': that set was not found. :(", name, set);
|
||||
throw new NoSuchElementException(err);
|
||||
}
|
||||
// 2. Find the card itself
|
||||
CardPrinted[] cards = cardsFromset.get(name);
|
||||
if (null == cards) {
|
||||
String err = String.format("Asked for card '%s' from '%s': set found, but the card wasn't. :(", name, set);
|
||||
throw new NoSuchElementException(err);
|
||||
}
|
||||
// 3. Get the proper copy
|
||||
if (artIndex > 0 && artIndex <= cards.length) { return cards[artIndex-1]; }
|
||||
String err = String.format("Asked for '%s' from '%s' #%d: db didn't find that copy. Note: artIndex is 1-based", name, set, artIndex);
|
||||
throw new NoSuchElementException(err);
|
||||
}
|
||||
|
||||
// Fetch from Forge's Card instance. Well, there should be no errors, but we'll still check
|
||||
public CardPrinted getCard(final Card forgeCard) {
|
||||
String name = forgeCard.getName();
|
||||
String set = forgeCard.getCurSetCode();
|
||||
if (StringUtils.isNotBlank(set)) { return getCard(name, set); }
|
||||
return getCard(name);
|
||||
}
|
||||
|
||||
// Multiple fetch
|
||||
public List<CardPrinted> getCards(final List<String> names) {
|
||||
List<CardPrinted> result = new ArrayList<CardPrinted>();
|
||||
for (String name : names) { result.add(getCard(name)); }
|
||||
return result;
|
||||
}
|
||||
|
||||
// returns a list of all cards from their respective latest editions
|
||||
public Iterable<CardPrinted> getAllUniqueCards() {
|
||||
return uniqueCards.values();
|
||||
}
|
||||
|
||||
public List<CardPrinted> getAllCards() { return allCardsFlat; }
|
||||
|
||||
}
|
||||
45
src/main/java/forge/card/CardInSet.java
Normal file
45
src/main/java/forge/card/CardInSet.java
Normal file
@@ -0,0 +1,45 @@
|
||||
package forge.card;
|
||||
|
||||
/**
|
||||
* <p>CardInSet class.</p>
|
||||
*
|
||||
* @author Forge
|
||||
* @version $Id: CardInSet.java 9708 2011-08-09 19:34:12Z jendave $
|
||||
*/
|
||||
|
||||
public class CardInSet {
|
||||
private CardRarity rarity;
|
||||
private int numCopies;
|
||||
|
||||
public CardInSet(final CardRarity rarity, final int cntCopies) {
|
||||
this.rarity = rarity;
|
||||
this.numCopies = cntCopies;
|
||||
}
|
||||
|
||||
public static CardInSet parse(final String unparsed) {
|
||||
int spaceAt = unparsed.indexOf(' ');
|
||||
char rarity = unparsed.charAt(spaceAt + 1);
|
||||
CardRarity rating;
|
||||
switch (rarity) {
|
||||
case 'L': rating = CardRarity.BasicLand; break;
|
||||
case 'C': rating = CardRarity.Common; break;
|
||||
case 'U': rating = CardRarity.Uncommon; break;
|
||||
case 'R': rating = CardRarity.Rare; break;
|
||||
case 'M': rating = CardRarity.MythicRare; break;
|
||||
case 'S': rating = CardRarity.Special; break;
|
||||
default: rating = CardRarity.MythicRare; break;
|
||||
}
|
||||
|
||||
int number = 1;
|
||||
int bracketAt = unparsed.indexOf('(');
|
||||
if (-1 != bracketAt) {
|
||||
String sN = unparsed.substring(bracketAt + 2, bracketAt + 3);
|
||||
number = Integer.parseInt(sN);
|
||||
}
|
||||
return new CardInSet(rating, number);
|
||||
|
||||
}
|
||||
|
||||
public final int getCopiesCount() { return numCopies; }
|
||||
public final CardRarity getRarity() { return rarity; }
|
||||
}
|
||||
154
src/main/java/forge/card/CardManaCost.java
Normal file
154
src/main/java/forge/card/CardManaCost.java
Normal file
@@ -0,0 +1,154 @@
|
||||
package forge.card;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Hashtable;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
|
||||
/**
|
||||
* <p>CardManaCost class.</p>
|
||||
*
|
||||
* @author Forge
|
||||
* @version $Id: CardManaCost.java 9708 2011-08-09 19:34:12Z jendave $
|
||||
*/
|
||||
|
||||
|
||||
public final class CardManaCost implements Comparable<CardManaCost> {
|
||||
private final List<CardManaCostShard> shards = new ArrayList<CardManaCostShard>();
|
||||
private final int genericCost;
|
||||
private final boolean isEmpty; // lands cost
|
||||
private final String stringValue; // precalculated for toString;
|
||||
|
||||
private Float compareWeight = null;
|
||||
|
||||
|
||||
// pass mana cost parser here
|
||||
private CardManaCost() {
|
||||
isEmpty = true;
|
||||
genericCost = 0;
|
||||
stringValue = "";
|
||||
}
|
||||
|
||||
public static final CardManaCost empty = new CardManaCost();
|
||||
|
||||
public CardManaCost(final String cost) {
|
||||
ParserMtgData parser = new ParserMtgData(cost);
|
||||
if (!parser.hasNext()) {
|
||||
throw new RuntimeException("Empty manacost passed to parser (this should have been handled before)");
|
||||
}
|
||||
isEmpty = false;
|
||||
while (parser.hasNext()) {
|
||||
CardManaCostShard shard = parser.next();
|
||||
if (shard != null) { shards.add(shard); } // null is OK - that was generic mana
|
||||
}
|
||||
genericCost = parser.getColorlessCost(); // collect generic mana here
|
||||
stringValue = getSimpleString();
|
||||
}
|
||||
|
||||
private String getSimpleString() {
|
||||
if (shards.isEmpty()) return Integer.toString(genericCost);
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
boolean isFirst = false;
|
||||
if (genericCost > 0) { sb.append(genericCost); isFirst = false; }
|
||||
for (CardManaCostShard s : shards) {
|
||||
if ( !isFirst ) { sb.append(' '); }
|
||||
else { isFirst = false; }
|
||||
sb.append(s.toString());
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public int getCMC() {
|
||||
int sum = 0;
|
||||
for (CardManaCostShard s : shards) { sum += s.cmc; }
|
||||
return sum + genericCost;
|
||||
}
|
||||
|
||||
public byte getColorProfile() {
|
||||
byte result = 0;
|
||||
for (CardManaCostShard s : shards) { result |= s.getColorMask(); }
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(final CardManaCost o) { return getCompareWeight().compareTo(o.getCompareWeight()); }
|
||||
private Float getCompareWeight() {
|
||||
if (compareWeight == null) {
|
||||
float weight = genericCost;
|
||||
for (CardManaCostShard s : shards) { weight += s.cmpc; }
|
||||
if (isEmpty) {
|
||||
weight = -1; // for those who doesn't even have a 0 sign on card
|
||||
}
|
||||
compareWeight = Float.valueOf(weight);
|
||||
}
|
||||
return compareWeight;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return stringValue;
|
||||
}
|
||||
|
||||
public class ParserMtgData implements Iterator<CardManaCostShard> {
|
||||
private final String cost;
|
||||
|
||||
private int nextBracket;
|
||||
private int colorlessCost;
|
||||
|
||||
|
||||
public ParserMtgData(final String cost) {
|
||||
this.cost = cost;
|
||||
// System.out.println(cost);
|
||||
nextBracket = cost.indexOf('{');
|
||||
colorlessCost = 0;
|
||||
}
|
||||
|
||||
public int getColorlessCost() {
|
||||
if ( hasNext() ) {
|
||||
throw new RuntimeException("Colorless cost should be obtained after iteration is complete");
|
||||
}
|
||||
return colorlessCost;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasNext() { return nextBracket != -1; }
|
||||
|
||||
@Override
|
||||
public CardManaCostShard next() {
|
||||
int closeBracket = cost.indexOf('}', nextBracket);
|
||||
String unparsed = cost.substring(nextBracket + 1, closeBracket);
|
||||
nextBracket = cost.indexOf('{', closeBracket + 1);
|
||||
|
||||
// System.out.println(unparsed);
|
||||
if (StringUtils.isNumeric(unparsed)) {
|
||||
colorlessCost += Integer.parseInt(unparsed);
|
||||
return null;
|
||||
}
|
||||
|
||||
int atoms = 0;
|
||||
for (int iChar = 0; iChar < unparsed.length(); iChar++) {
|
||||
switch (unparsed.charAt(iChar)) {
|
||||
case 'W': atoms |= CardManaCostShard.Atom.WHITE; break;
|
||||
case 'U': atoms |= CardManaCostShard.Atom.BLUE; break;
|
||||
case 'B': atoms |= CardManaCostShard.Atom.BLACK; break;
|
||||
case 'R': atoms |= CardManaCostShard.Atom.RED; break;
|
||||
case 'G': atoms |= CardManaCostShard.Atom.GREEN; break;
|
||||
case '2': atoms |= CardManaCostShard.Atom.OR_2_COLORLESS; break;
|
||||
case 'P': atoms |= CardManaCostShard.Atom.OR_2_LIFE; break;
|
||||
case 'X': atoms |= CardManaCostShard.Atom.IS_X; break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
return CardManaCostShard.valueOf(atoms);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove() { } // unsuported
|
||||
}
|
||||
}
|
||||
|
||||
124
src/main/java/forge/card/CardManaCostShard.java
Normal file
124
src/main/java/forge/card/CardManaCostShard.java
Normal file
@@ -0,0 +1,124 @@
|
||||
package forge.card;
|
||||
|
||||
import forge.card.mana.ManaCost;
|
||||
|
||||
public class CardManaCostShard {
|
||||
|
||||
private final int shard;
|
||||
public final int cmc;
|
||||
public final float cmpc;
|
||||
private final String stringValue;
|
||||
protected CardManaCostShard(int value, String sValue) {
|
||||
shard = value;
|
||||
cmc = getCMC();
|
||||
cmpc = getCmpCost();
|
||||
stringValue = sValue;
|
||||
}
|
||||
|
||||
public interface Atom {
|
||||
//int COLORLESS = 1 << 0;
|
||||
int WHITE = 1 << 1;
|
||||
int BLUE = 1 << 2;
|
||||
int BLACK = 1 << 3;
|
||||
int RED = 1 << 4;
|
||||
int GREEN = 1 << 5;
|
||||
|
||||
int IS_X = 1 << 8;
|
||||
int OR_2_COLORLESS = 1 << 9;
|
||||
int OR_2_LIFE = 1 << 10;
|
||||
|
||||
}
|
||||
|
||||
/* Why boxed values are here?
|
||||
* They is meant to be constant and require no further boxing if added into an arraylist or something else,
|
||||
* with generic parameters that would require Object's descendant.
|
||||
*
|
||||
* Choosing between "let's have some boxing" and "let's have some unboxing",
|
||||
* I choose the latter,
|
||||
* because memory for boxed objects will be taken from heap,
|
||||
* while unboxed values will lay on stack, which is faster
|
||||
*/
|
||||
public static final CardManaCostShard X = new CardManaCostShard(Atom.IS_X, "X");
|
||||
|
||||
public static final CardManaCostShard WHITE = new CardManaCostShard(Atom.WHITE, "W");
|
||||
public static final CardManaCostShard BLUE = new CardManaCostShard(Atom.BLUE, "U");
|
||||
public static final CardManaCostShard BLACK = new CardManaCostShard(Atom.BLACK, "B");
|
||||
public static final CardManaCostShard RED = new CardManaCostShard(Atom.RED, "R");
|
||||
public static final CardManaCostShard GREEN = new CardManaCostShard(Atom.GREEN, "G");
|
||||
|
||||
public static final CardManaCostShard PW = new CardManaCostShard(Atom.WHITE | Atom.OR_2_LIFE, "W/P");
|
||||
public static final CardManaCostShard PU = new CardManaCostShard(Atom.BLUE | Atom.OR_2_LIFE, "U/P");
|
||||
public static final CardManaCostShard PB = new CardManaCostShard(Atom.BLACK | Atom.OR_2_LIFE, "B/P");
|
||||
public static final CardManaCostShard PR = new CardManaCostShard(Atom.RED | Atom.OR_2_LIFE, "R/P");
|
||||
public static final CardManaCostShard PG = new CardManaCostShard(Atom.GREEN | Atom.OR_2_LIFE, "G/P");
|
||||
|
||||
public static final CardManaCostShard WU = new CardManaCostShard(Atom.WHITE | Atom.BLUE, "W/U");
|
||||
public static final CardManaCostShard WB = new CardManaCostShard(Atom.WHITE | Atom.BLACK, "W/B");
|
||||
public static final CardManaCostShard WR = new CardManaCostShard(Atom.WHITE | Atom.RED, "W/R");
|
||||
public static final CardManaCostShard WG = new CardManaCostShard(Atom.WHITE | Atom.GREEN, "W/G");
|
||||
public static final CardManaCostShard UB = new CardManaCostShard(Atom.BLUE | Atom.BLACK, "U/B");
|
||||
public static final CardManaCostShard UR = new CardManaCostShard(Atom.BLUE | Atom.RED, "U/R");
|
||||
public static final CardManaCostShard UG = new CardManaCostShard(Atom.BLUE | Atom.GREEN, "U/G");
|
||||
public static final CardManaCostShard BR = new CardManaCostShard(Atom.BLACK | Atom.RED, "B/R");
|
||||
public static final CardManaCostShard BG = new CardManaCostShard(Atom.BLACK | Atom.GREEN, "B/G");
|
||||
public static final CardManaCostShard RG = new CardManaCostShard(Atom.RED | Atom.GREEN, "R/G");
|
||||
|
||||
public static final CardManaCostShard W2 = new CardManaCostShard(Atom.WHITE | Atom.OR_2_COLORLESS, "2/W");
|
||||
public static final CardManaCostShard U2 = new CardManaCostShard(Atom.BLUE | Atom.OR_2_COLORLESS, "2/U");
|
||||
public static final CardManaCostShard B2 = new CardManaCostShard(Atom.BLACK | Atom.OR_2_COLORLESS, "2/B");
|
||||
public static final CardManaCostShard R2 = new CardManaCostShard(Atom.RED | Atom.OR_2_COLORLESS, "2/R");
|
||||
public static final CardManaCostShard G2 = new CardManaCostShard(Atom.GREEN | Atom.OR_2_COLORLESS, "2/G");
|
||||
|
||||
private static final CardManaCostShard[] allPossible = new CardManaCostShard[] {
|
||||
X, WHITE, BLUE, BLACK, RED, GREEN,
|
||||
PW, PU, PB, PR, PG,
|
||||
WU, WB, WR, WG, UB, UR, UG, BR, BG, RG,
|
||||
W2, U2, B2, R2, G2
|
||||
};
|
||||
|
||||
private int getCMC() {
|
||||
if (0 != (shard & Atom.IS_X)) { return 0; }
|
||||
if (0 != (shard & Atom.OR_2_COLORLESS)) { return 2; }
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns Mana cost, adjusted slightly to make colored mana parts more significant.
|
||||
* Should only be used for comparison purposes; using this method allows the sort:
|
||||
* 2 < X 2 < 1 U < U U < UR U < X U U < X X U U
|
||||
*
|
||||
* @return The converted cost + 0.0005* the number of colored mana in the cost + 0.00001 *
|
||||
* the number of X's in the cost
|
||||
*/
|
||||
private float getCmpCost() {
|
||||
if (0 != (shard & Atom.IS_X)) { return 0.0001f; }
|
||||
float cost = 0 != (shard & Atom.OR_2_COLORLESS) ? 2 : 1;
|
||||
// yes, these numbers are magic, slightly-magic
|
||||
if (0 != (shard & Atom.WHITE)) { cost += 0.0005f; }
|
||||
if (0 != (shard & Atom.BLUE)) { cost += 0.0020f; }
|
||||
if (0 != (shard & Atom.BLACK)) { cost += 0.0080f; }
|
||||
if (0 != (shard & Atom.RED)) { cost += 0.0320f; }
|
||||
if (0 != (shard & Atom.GREEN)) { cost += 0.1280f; }
|
||||
return cost;
|
||||
}
|
||||
|
||||
final byte getColorMask() {
|
||||
byte result = 0;
|
||||
if (0 != (shard & Atom.WHITE)) { result |= CardColor.WHITE; }
|
||||
if (0 != (shard & Atom.BLUE)) { result |= CardColor.BLUE; }
|
||||
if (0 != (shard & Atom.BLACK)) { result |= CardColor.BLACK; }
|
||||
if (0 != (shard & Atom.RED)) { result |= CardColor.RED; }
|
||||
if (0 != (shard & Atom.GREEN)) { result |= CardColor.GREEN; }
|
||||
return result;
|
||||
}
|
||||
|
||||
public static CardManaCostShard valueOf(final int atoms) {
|
||||
for (int i = 0; i < allPossible.length; i++) {
|
||||
if (allPossible[i].shard == atoms) { return allPossible[i]; }
|
||||
}
|
||||
throw new RuntimeException(String.format("Not fount: mana shard with profile = %x", atoms));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() { return stringValue; }
|
||||
}
|
||||
67
src/main/java/forge/card/CardPool.java
Normal file
67
src/main/java/forge/card/CardPool.java
Normal file
@@ -0,0 +1,67 @@
|
||||
package forge.card;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Hashtable;
|
||||
import java.util.List;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
/**
|
||||
* <p>CardPool class.</p>
|
||||
*
|
||||
* @author Forge
|
||||
* @version $Id: CardReference.java 9708 2011-08-09 19:34:12Z jendave $
|
||||
*/
|
||||
public final class CardPool extends CardPoolView {
|
||||
|
||||
// Contructors here
|
||||
public CardPool() { super(); }
|
||||
public CardPool(final List<String> names) { super(); addAllCards(CardDb.instance().getCards(names)); }
|
||||
|
||||
// Copy ctor will create its own modifiable pool
|
||||
@SuppressWarnings("unchecked")
|
||||
public CardPool(final CardPoolView from) {
|
||||
super();
|
||||
cards = (Hashtable<CardPrinted, Integer>) ((Hashtable<CardPrinted, Integer>) (from.cards)).clone();
|
||||
}
|
||||
public CardPool(final Iterable<CardPrinted> list) {
|
||||
this(); addAllCards(list);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// get
|
||||
public CardPoolView getView() { return new CardPoolView(Collections.unmodifiableMap(cards)); }
|
||||
|
||||
// Cards manipulation
|
||||
public void add(final CardPrinted card) { add(card, 1); }
|
||||
public void add(final CardPrinted card, final int amount) {
|
||||
cards.put(card, count(card) + amount);
|
||||
isListInSync = false;
|
||||
}
|
||||
public void addAllCards(final Iterable<CardPrinted> cards) {
|
||||
for (CardPrinted cr : cards) { add(cr); }
|
||||
isListInSync = false;
|
||||
}
|
||||
public void addAll(final Iterable<Entry<CardPrinted, Integer>> map) {
|
||||
for (Entry<CardPrinted, Integer> e : map) { add(e.getKey(), e.getValue()); }
|
||||
isListInSync = false;
|
||||
}
|
||||
public void addAll(final Entry<CardPrinted, Integer>[] map) {
|
||||
for (Entry<CardPrinted, Integer> e : map) { add(e.getKey(), e.getValue()); }
|
||||
isListInSync = false;
|
||||
}
|
||||
|
||||
public void remove(final CardPrinted card) { remove(card, 1); }
|
||||
public void remove(final CardPrinted card, final int amount) {
|
||||
int count = count(card);
|
||||
if (count <= amount) { cards.remove(card); }
|
||||
else { cards.put(card, count - amount); }
|
||||
isListInSync = false;
|
||||
}
|
||||
public void removeAll(final Iterable<Entry<CardPrinted, Integer>> map) {
|
||||
for (Entry<CardPrinted, Integer> e : map) { remove(e.getKey(), e.getValue()); }
|
||||
isListInSync = false;
|
||||
}
|
||||
|
||||
public void clear() { cards.clear(); isListInSync = false; }
|
||||
}
|
||||
94
src/main/java/forge/card/CardPoolView.java
Normal file
94
src/main/java/forge/card/CardPoolView.java
Normal file
@@ -0,0 +1,94 @@
|
||||
package forge.card;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Hashtable;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import forge.CardList;
|
||||
|
||||
import net.slightlymagic.braids.util.lambda.Lambda1;
|
||||
|
||||
/**
|
||||
* <p>CardPoolView class.</p>
|
||||
*
|
||||
* @author Forge
|
||||
* @version $Id: CardPoolView.java 9708 2011-08-09 19:34:12Z jendave $
|
||||
*/
|
||||
public class CardPoolView implements Iterable<Entry<CardPrinted, Integer>> {
|
||||
|
||||
// Field Accessors for select/aggregate operations with filters.
|
||||
public final static Lambda1<CardRules, Entry<CardPrinted, Integer>> fnToCard =
|
||||
new Lambda1<CardRules, Entry<CardPrinted, Integer>>() {
|
||||
@Override public CardRules apply(final Entry<CardPrinted, Integer> from) { return from.getKey().getCard(); }
|
||||
};
|
||||
public final static Lambda1<CardPrinted, Entry<CardPrinted, Integer>> fnToReference =
|
||||
new Lambda1<CardPrinted, Entry<CardPrinted, Integer>>() {
|
||||
@Override public CardPrinted apply(final Entry<CardPrinted, Integer> from) { return from.getKey(); }
|
||||
};
|
||||
|
||||
public final static Lambda1<Integer, Entry<CardPrinted, Integer>> fnToCount =
|
||||
new Lambda1<Integer, Entry<CardPrinted, Integer>>() {
|
||||
@Override public Integer apply(final Entry<CardPrinted, Integer> from) { return from.getValue(); }
|
||||
};
|
||||
|
||||
// Constructors
|
||||
public CardPoolView() { cards = new Hashtable<CardPrinted, Integer>(); }
|
||||
public CardPoolView(final Map<CardPrinted, Integer> inMap) { cards = inMap; }
|
||||
|
||||
// Data members
|
||||
protected Map<CardPrinted, Integer> cards;
|
||||
|
||||
// same thing as above, it was copied to provide sorting (needed by table views in deck editors)
|
||||
protected List<Entry<CardPrinted, Integer>> cardsListOrdered = new ArrayList<Map.Entry<CardPrinted,Integer>>();
|
||||
protected boolean isListInSync = false;
|
||||
|
||||
@Override
|
||||
public final Iterator<Entry<CardPrinted, Integer>> iterator() { return cards.entrySet().iterator(); }
|
||||
|
||||
// Cards manipulation
|
||||
public final int count(final CardPrinted card) {
|
||||
if (cards == null) { return 0; }
|
||||
Integer boxed = cards.get(card);
|
||||
return boxed == null ? 0 : boxed.intValue();
|
||||
}
|
||||
public final int countAll() {
|
||||
int result = 0;
|
||||
if (cards != null) { for (Integer n : cards.values()) { result += n; } }
|
||||
return result;
|
||||
}
|
||||
public final int countDistinct() { return cards.size(); }
|
||||
|
||||
public final List<Entry<CardPrinted, Integer>> getOrderedList() {
|
||||
if (!isListInSync) {
|
||||
cardsListOrdered.clear();
|
||||
if (cards != null) {
|
||||
for (Entry<CardPrinted, Integer> e : cards.entrySet()) {
|
||||
cardsListOrdered.add(e);
|
||||
}
|
||||
}
|
||||
isListInSync = true;
|
||||
}
|
||||
return cardsListOrdered;
|
||||
}
|
||||
|
||||
public final List<CardPrinted> toFlatList() {
|
||||
List<CardPrinted> result = new ArrayList<CardPrinted>();
|
||||
for (Entry<CardPrinted, Integer> e : this) {
|
||||
for (int i = 0; i < e.getValue(); i++) { result.add(e.getKey()); }
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public final CardList toForgeCardList() {
|
||||
CardList result = new CardList();
|
||||
for (Entry<CardPrinted, Integer> e : this) {
|
||||
for (int i = 0; i < e.getValue(); i++) {
|
||||
result.add(e.getKey().toForgeCard());
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
166
src/main/java/forge/card/CardPrinted.java
Normal file
166
src/main/java/forge/card/CardPrinted.java
Normal file
@@ -0,0 +1,166 @@
|
||||
package forge.card;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import org.apache.commons.lang3.ArrayUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import net.slightlymagic.braids.util.lambda.Lambda1;
|
||||
import net.slightlymagic.maxmtg.Predicate;
|
||||
import forge.AllZone;
|
||||
import forge.Card;
|
||||
|
||||
/**
|
||||
* <p>CardReference class.</p>
|
||||
*
|
||||
* @author Forge
|
||||
* @version $Id: CardReference.java 9708 2011-08-09 19:34:12Z jendave $
|
||||
*/
|
||||
public final class CardPrinted implements Comparable<CardPrinted> {
|
||||
// Reference to rules
|
||||
private final transient CardRules card;
|
||||
|
||||
// These fields are kinda PK for PrintedCard
|
||||
private final String name;
|
||||
private final String cardSet;
|
||||
private final int artIndex;
|
||||
private final boolean foiled;
|
||||
|
||||
// Calculated fields are below:
|
||||
private final transient CardRarity rarity; // rarity is given in ctor when set is assigned
|
||||
|
||||
// need this to be sure that different cased names won't break the system (and create uniqie cardref entries)
|
||||
private final transient String _name_lcase;
|
||||
|
||||
// field RO accessors
|
||||
public String getName() { return name; }
|
||||
public String getSet() { return cardSet; }
|
||||
public int getArtIndex() { return artIndex; }
|
||||
public boolean isFoil() { return foiled; }
|
||||
public CardRules getCard() { return card; }
|
||||
public CardRarity getRarity() { return rarity; }
|
||||
|
||||
|
||||
// Lambda to get rules for selects from list of printed cards
|
||||
public static final Lambda1<CardRules, CardPrinted> fnGetRules = new Lambda1<CardRules, CardPrinted>() {
|
||||
@Override public CardRules apply(final CardPrinted from) { return from.card; }
|
||||
};
|
||||
|
||||
// Constructor is private. All non-foiled instances are stored in CardDb
|
||||
private CardPrinted(final CardRules c, final String set, final CardRarity rare, final int index, boolean foil) {
|
||||
card = c;
|
||||
name = c.getName();
|
||||
cardSet = set;
|
||||
artIndex = index;
|
||||
foiled = foil;
|
||||
rarity = rare;
|
||||
_name_lcase = name.toLowerCase();
|
||||
}
|
||||
|
||||
/* package visibility */
|
||||
static CardPrinted build(final CardRules c, final String set, final CardRarity rare, final int index) {
|
||||
return new CardPrinted(c, set, rare, index, false);
|
||||
}
|
||||
|
||||
/* foiled don't need to stay in CardDb's structures, so u'r free to create */
|
||||
public static CardPrinted makeFoiled(final CardPrinted c) {
|
||||
return new CardPrinted(c.card, c.cardSet, c.rarity, c.artIndex, true);
|
||||
}
|
||||
|
||||
// Want this class to be a key for HashTable
|
||||
@Override
|
||||
public boolean equals(final Object obj) {
|
||||
if (this == obj) { return true; }
|
||||
if (obj == null) { return false; }
|
||||
if (getClass() != obj.getClass()) { return false; }
|
||||
|
||||
CardPrinted other = (CardPrinted) obj;
|
||||
if (!name.equals(other.name)) { return false; }
|
||||
if (!cardSet.equals(other.cardSet)) { return false; }
|
||||
if (other.foiled != this.foiled || other.artIndex != this.artIndex) { return false; }
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int code = _name_lcase.hashCode() * 11 + cardSet.hashCode() * 59 + artIndex * 2;
|
||||
if (foiled) { return code + 1; }
|
||||
return code;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format("%s|%s", name, cardSet);
|
||||
}
|
||||
|
||||
public Card toForgeCard() {
|
||||
Card c = AllZone.getCardFactory().getCard(name, null);
|
||||
c.setCurSetCode(getSet());
|
||||
return c;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(final CardPrinted o) {
|
||||
int nameCmp = _name_lcase.compareTo(o._name_lcase);
|
||||
if (0 != nameCmp) { return nameCmp; }
|
||||
// TODO: compare sets properly
|
||||
return cardSet.compareTo(o.cardSet);
|
||||
}
|
||||
|
||||
|
||||
public static abstract class Predicates {
|
||||
public static Predicate<CardPrinted> rarity(final boolean isEqual, final CardRarity value)
|
||||
{
|
||||
return new PredicateRarity(value, isEqual);
|
||||
}
|
||||
public static Predicate<CardPrinted> printedInSets(final String[] value)
|
||||
{
|
||||
return new PredicateSets(value);
|
||||
}
|
||||
|
||||
private static class PredicateRarity extends Predicate<CardPrinted> {
|
||||
private final CardRarity operand;
|
||||
private final boolean shouldBeEqual;
|
||||
|
||||
@Override
|
||||
public boolean isTrue(final CardPrinted card) {
|
||||
return card.rarity.equals(operand) == shouldBeEqual;
|
||||
}
|
||||
|
||||
public PredicateRarity(final CardRarity type, final boolean wantEqual) {
|
||||
operand = type;
|
||||
shouldBeEqual = wantEqual;
|
||||
}
|
||||
}
|
||||
|
||||
private static class PredicateSets extends Predicate<CardPrinted> {
|
||||
private final String[] sets;
|
||||
@Override public boolean isTrue(final CardPrinted card) {
|
||||
return Arrays.binarySearch(sets, card.rarity) >= 0;
|
||||
}
|
||||
public PredicateSets(final String[] wantSets) {
|
||||
sets = wantSets.clone();
|
||||
Arrays.sort(sets);
|
||||
}
|
||||
}
|
||||
|
||||
public abstract static class Presets {
|
||||
// Think twice before using these, since rarity is a prop of printed card.
|
||||
public static final Predicate<CardPrinted> isCommon = rarity(true, CardRarity.Common);
|
||||
public static final Predicate<CardPrinted> isUncommon = rarity(true, CardRarity.Uncommon);
|
||||
public static final Predicate<CardPrinted> isRare = rarity(true, CardRarity.Rare);
|
||||
public static final Predicate<CardPrinted> isMythicRare = rarity(true, CardRarity.MythicRare);
|
||||
public static final Predicate<CardPrinted> isRareOrMythic = Predicate.or(isRare, isMythicRare);
|
||||
|
||||
public static final Predicate<CardPrinted> isSpecial = rarity(true, CardRarity.Special);
|
||||
|
||||
public static final Predicate<CardPrinted> exceptLands = rarity(false, CardRarity.BasicLand);
|
||||
|
||||
// TODO: Update this code on each rotation (or move this list to a file)
|
||||
public static final Predicate<CardPrinted> isStandard = printedInSets(
|
||||
new String[] {"M12", "NPH", "MBS", "SOM", "M11", "ROE", "WWK", "ZEN"});
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
28
src/main/java/forge/card/CardRarity.java
Normal file
28
src/main/java/forge/card/CardRarity.java
Normal file
@@ -0,0 +1,28 @@
|
||||
package forge.card;
|
||||
|
||||
/**
|
||||
* <p>CardRarity class.</p>
|
||||
*
|
||||
* @author Forge
|
||||
* @version $Id: CardRarity.java 9708 2011-08-09 19:34:12Z jendave $
|
||||
*/
|
||||
|
||||
public enum CardRarity {
|
||||
BasicLand(0, "L"),
|
||||
Common(1, "C"),
|
||||
Uncommon(2, "U"),
|
||||
Rare(3, "R"),
|
||||
MythicRare(4, "M"),
|
||||
Special(10, "S"); // Timeshifted
|
||||
|
||||
private final int rating;
|
||||
private final String strValue;
|
||||
private CardRarity(final int value, final String sValue) {
|
||||
rating = value;
|
||||
strValue = sValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() { return strValue; }
|
||||
|
||||
}
|
||||
@@ -1,89 +0,0 @@
|
||||
package forge.card;
|
||||
|
||||
import java.security.InvalidParameterException;
|
||||
import java.util.ArrayList;
|
||||
|
||||
import forge.AllZone;
|
||||
import forge.Card;
|
||||
import forge.SetInfo;
|
||||
|
||||
/**
|
||||
* <p>CardReference class.</p>
|
||||
*
|
||||
* @author Forge
|
||||
* @version $Id: CardReference.java 9708 2011-08-09 19:34:12Z jendave $
|
||||
*/
|
||||
public final class CardReference {
|
||||
private static final boolean ENABLE_CONSISTENCY_CHECK = true;
|
||||
|
||||
private String name;
|
||||
private String cardSet;
|
||||
private short pictureNumber = 0;
|
||||
private boolean foiled = false;
|
||||
|
||||
public CardReference(final String named, final String set, final int picNum, final boolean foil) {
|
||||
this(named, set, picNum);
|
||||
foiled = foil;
|
||||
}
|
||||
|
||||
public CardReference(final String named, final String set, final int picNum) {
|
||||
this(named, set);
|
||||
pictureNumber = (short) picNum;
|
||||
}
|
||||
|
||||
public CardReference(final String named, final String set) {
|
||||
name = named;
|
||||
cardSet = set;
|
||||
|
||||
if (set == null || ENABLE_CONSISTENCY_CHECK) {
|
||||
Card c = AllZone.getCardFactory().getCard(name, null);
|
||||
if (c == null) {
|
||||
String error = String.format("Invalid reference! The card named '%s' is unknown to Forge", name);
|
||||
throw new InvalidParameterException(error);
|
||||
}
|
||||
|
||||
ArrayList<SetInfo> validSets = c.getSets();
|
||||
boolean isSetValid = false;
|
||||
if (cardSet != null) {
|
||||
for (SetInfo si : validSets) {
|
||||
if (si.Code.equals(set)) { isSetValid = true; break; }
|
||||
}
|
||||
}
|
||||
|
||||
if (!isSetValid) {
|
||||
cardSet = c.getMostRecentSet();
|
||||
// String error = String.format("The card '%s' is not a part of '%s' set", name, set);
|
||||
// throw new InvalidParameterException(error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public CardReference(final String named) { this(named, (String) null); }
|
||||
|
||||
public String getName() { return name; }
|
||||
public String getSet() { return cardSet; }
|
||||
public short getPictureIndex() { return pictureNumber; }
|
||||
public boolean isFoil() { return foiled; }
|
||||
|
||||
// Want this class to be a key for HashTable
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) { return true; }
|
||||
if (obj == null) { return false; }
|
||||
if (getClass() != obj.getClass()) { return false; }
|
||||
|
||||
CardReference other = (CardReference) obj;
|
||||
if (!name.equals(other.name)) { return false; }
|
||||
if (!cardSet.equals(other.cardSet)) { return false; }
|
||||
if (other.foiled != this.foiled || other.pictureNumber != this.pictureNumber) { return false; }
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int code = name.hashCode() * 11 + cardSet.hashCode() * 59 + pictureNumber * 2;
|
||||
if (foiled) { return code + 1; }
|
||||
return code;
|
||||
}
|
||||
}
|
||||
348
src/main/java/forge/card/CardRules.java
Normal file
348
src/main/java/forge/card/CardRules.java
Normal file
@@ -0,0 +1,348 @@
|
||||
package forge.card;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
|
||||
import net.slightlymagic.maxmtg.Predicate;
|
||||
import net.slightlymagic.maxmtg.Predicate.ComparableOp;
|
||||
import net.slightlymagic.maxmtg.Predicate.PredicatesOp;
|
||||
import net.slightlymagic.maxmtg.Predicate.StringOp;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
/**
|
||||
* <p>CardOracle class.</p>
|
||||
*
|
||||
* @author Forge
|
||||
* @version $Id: CardOracle.java 9708 2011-08-09 19:34:12Z jendave $
|
||||
*/
|
||||
public final class CardRules {
|
||||
private final String name;
|
||||
private final CardType type;
|
||||
private final CardManaCost cost;
|
||||
private CardColor color = null; // color is subject to change yet (parse %cardname% is %color% rule)
|
||||
private final String[] rules;
|
||||
|
||||
private int iPower = -1;
|
||||
private int iToughness = -1;
|
||||
private String power = null;
|
||||
private String toughness = null;
|
||||
|
||||
private String loyalty = null;
|
||||
|
||||
private HashMap<String, CardInSet> setsPrinted = null;
|
||||
|
||||
// Ctor and builders are needed here
|
||||
public String getName() { return name; }
|
||||
public CardType getType() { return type; }
|
||||
public CardManaCost getManaCost() { return cost; }
|
||||
public CardColor getColor() { return color; }
|
||||
public String[] getRules() { return rules; }
|
||||
public Set<Entry<String, CardInSet>> getSetsPrinted() { return setsPrinted.entrySet(); }
|
||||
|
||||
public String getPower() { return power; }
|
||||
public int getIntPower() { return iPower; }
|
||||
public String getToughness() { return toughness; }
|
||||
public int getIntToughness() { return iToughness; }
|
||||
public String getLoyalty() { return loyalty; }
|
||||
|
||||
public String getPTorLoyalty() {
|
||||
if (getType().isCreature()) { return power + "/" + toughness; }
|
||||
if (getType().isPlaneswalker()) { return loyalty; }
|
||||
return "";
|
||||
}
|
||||
|
||||
public CardRules(final String cardName, final CardType cardType, final String manacost,
|
||||
final String ptLine, final String[] cardRules, final String[] setsData)
|
||||
{
|
||||
this.name = cardName;
|
||||
this.type = cardType;
|
||||
this.cost = manacost == null ? CardManaCost.empty : new CardManaCost(manacost);
|
||||
this.rules = cardRules;
|
||||
this.color = new CardColor(cost);
|
||||
if (cardType.isCreature()) {
|
||||
int slashPos = ptLine.indexOf('/');
|
||||
if (slashPos == -1) {
|
||||
throw new RuntimeException(String.format("Creature '%s' has bad p/t stats", cardName));
|
||||
}
|
||||
this.power = ptLine.substring(0, slashPos);
|
||||
this.toughness = ptLine.substring(slashPos + 1, ptLine.length());
|
||||
this.iPower = StringUtils.isNumeric(power) ? Integer.parseInt(power) : 0;
|
||||
this.iToughness = StringUtils.isNumeric(toughness) ? Integer.parseInt(toughness) : 0;
|
||||
} else if (cardType.isPlaneswalker()) {
|
||||
this.loyalty = ptLine;
|
||||
}
|
||||
|
||||
this.setsPrinted = new HashMap<String, CardInSet>();
|
||||
for (int iSet = 0; iSet < setsData.length; iSet++) {
|
||||
String setCode = setsData[iSet].substring(0, setsData[iSet].indexOf(' '));
|
||||
setsPrinted.put(setCode, CardInSet.parse(setsData[iSet]));
|
||||
}
|
||||
}
|
||||
|
||||
public boolean rulesContain(final String text) {
|
||||
for (String r : rules) { if (r.contains(text)) { return true; } }
|
||||
return false;
|
||||
}
|
||||
public String getLatestSetPrinted() {
|
||||
String lastSet = null;
|
||||
// TODO: Make a true release-date based sorting
|
||||
for (String cs : setsPrinted.keySet()) {
|
||||
lastSet = cs;
|
||||
}
|
||||
return lastSet;
|
||||
}
|
||||
public CardInSet getSetInfo(final String setCode) {
|
||||
CardInSet result = setsPrinted.get(setCode);
|
||||
if (result != null) { return result; }
|
||||
throw new RuntimeException(String.format("Card '%s' was never printed in set '%s'", name, setCode));
|
||||
|
||||
}
|
||||
public CardRarity getRarityFromLatestSet() {
|
||||
CardInSet cis = setsPrinted.get(getLatestSetPrinted());
|
||||
return cis.getRarity();
|
||||
}
|
||||
|
||||
public abstract static class Predicates {
|
||||
|
||||
// Static builder methods - they choose concrete implementation by themselves
|
||||
public static Predicate<CardRules> cmc(final ComparableOp op, final int what)
|
||||
{
|
||||
return new LeafNumber(LeafNumber.CardField.CMC, op, what);
|
||||
}
|
||||
// Power
|
||||
// Toughness
|
||||
public static Predicate<CardRules> rules(final StringOp op, final String what)
|
||||
{
|
||||
return new LeafString(LeafString.CardField.RULES, op, what);
|
||||
}
|
||||
public static Predicate<CardRules> name(final StringOp op, final String what)
|
||||
{
|
||||
return new LeafString(LeafString.CardField.NAME, op, what);
|
||||
}
|
||||
public static Predicate<CardRules> subType(final StringOp op, final String what)
|
||||
{
|
||||
return new LeafString(LeafString.CardField.SUBTYPE, op, what);
|
||||
}
|
||||
public static Predicate<CardRules> coreType(final boolean isEqual, final String what)
|
||||
{
|
||||
try { return coreType(isEqual, CardCoreType.valueOf(CardCoreType.class, what)); }
|
||||
catch (Exception e) { return Predicate.getFalse(CardRules.class); }
|
||||
}
|
||||
public static Predicate<CardRules> coreType(final boolean isEqual, final CardCoreType type)
|
||||
{
|
||||
return new PredicateCoreType(type, isEqual);
|
||||
}
|
||||
public static Predicate<CardRules> superType(final boolean isEqual, final String what)
|
||||
{
|
||||
try { return superType(isEqual, CardSuperType.valueOf(CardSuperType.class, what)); }
|
||||
catch (Exception e) { return Predicate.getFalse(CardRules.class); }
|
||||
}
|
||||
public static Predicate<CardRules> superType(final boolean isEqual, final CardSuperType type)
|
||||
{
|
||||
return new PredicateSuperType(type, isEqual);
|
||||
}
|
||||
public static Predicate<CardRules> rarityInCardsLatestSet(final boolean isEqual, final CardRarity value)
|
||||
{
|
||||
return new PredicateLastesSetRarity(value, isEqual);
|
||||
}
|
||||
public static Predicate<CardRules> hasColor(final byte thatColor) {
|
||||
return new LeafColor(LeafColor.ColorOperator.HasAllOf, thatColor);
|
||||
}
|
||||
public static Predicate<CardRules> isColor(final byte thatColor) {
|
||||
return new LeafColor(LeafColor.ColorOperator.HasAnyOf, thatColor);
|
||||
}
|
||||
public static Predicate<CardRules> hasCntColors(final byte cntColors) {
|
||||
return new LeafColor(LeafColor.ColorOperator.Equals, cntColors);
|
||||
}
|
||||
public static Predicate<CardRules> hasAtLeastCntColors(final byte cntColors) {
|
||||
return new LeafColor(LeafColor.ColorOperator.CountColorsGreaterOrEqual, cntColors);
|
||||
}
|
||||
|
||||
private static class LeafString extends Predicate<CardRules> {
|
||||
public enum CardField {
|
||||
RULES,
|
||||
NAME,
|
||||
SUBTYPE
|
||||
}
|
||||
|
||||
private final String operand;
|
||||
private final StringOp operator;
|
||||
private final CardField field;
|
||||
|
||||
@Override
|
||||
public boolean isTrue(final CardRules card) {
|
||||
boolean shouldConatin;
|
||||
switch (field) {
|
||||
case NAME:
|
||||
return op(card.getName(), operand);
|
||||
case SUBTYPE:
|
||||
shouldConatin = operator == StringOp.CONTAINS || operator == StringOp.EQUALS;
|
||||
return shouldConatin == card.getType().subTypeContains(operand);
|
||||
case RULES:
|
||||
shouldConatin = operator == StringOp.CONTAINS || operator == StringOp.EQUALS;
|
||||
return shouldConatin == card.rulesContain(operand);
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean op(final String op1, final String op2) {
|
||||
if (operator == StringOp.CONTAINS) { return op1.contains(op2); }
|
||||
if (operator == StringOp.NOT_CONTAINS) { return op1.contains(op2); }
|
||||
if (operator == StringOp.EQUALS) { return op1.equals(op2); }
|
||||
return false;
|
||||
}
|
||||
|
||||
public LeafString(final CardField field, final StringOp operator, final String operand)
|
||||
{
|
||||
this.field = field;
|
||||
this.operand = operand;
|
||||
this.operator = operator;
|
||||
}
|
||||
}
|
||||
|
||||
private static class LeafColor extends Predicate<CardRules> {
|
||||
public enum ColorOperator {
|
||||
CountColors,
|
||||
CountColorsGreaterOrEqual,
|
||||
HasAnyOf,
|
||||
HasAllOf,
|
||||
Equals
|
||||
}
|
||||
|
||||
private final ColorOperator op;
|
||||
private final byte color;
|
||||
|
||||
public LeafColor(final ColorOperator operator, final byte thatColor)
|
||||
{
|
||||
op = operator;
|
||||
color = thatColor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isTrue(final CardRules subject) {
|
||||
switch(op) {
|
||||
case CountColors: return subject.getColor().countColors() == color;
|
||||
case CountColorsGreaterOrEqual: return subject.getColor().countColors() >= color;
|
||||
case Equals: return subject.getColor().isEqual(color);
|
||||
case HasAllOf: return subject.getColor().hasAllColors(color);
|
||||
case HasAnyOf: return subject.getColor().hasAnyColor(color);
|
||||
default: return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class LeafNumber extends Predicate<CardRules> {
|
||||
protected enum CardField {
|
||||
CMC,
|
||||
POWER,
|
||||
TOUGHNESS,
|
||||
}
|
||||
|
||||
private final CardField field;
|
||||
private final ComparableOp operator;
|
||||
private final int operand;
|
||||
|
||||
public LeafNumber(final CardField field, final ComparableOp op, final int what) {
|
||||
this.field = field;
|
||||
operand = what;
|
||||
operator = op;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isTrue(final CardRules card) {
|
||||
int value;
|
||||
switch (field) {
|
||||
case CMC: return op(card.getManaCost().getCMC(), operand);
|
||||
case POWER: value = card.getIntPower(); return value >= 0 ? op(value, operand) : false;
|
||||
case TOUGHNESS: value = card.getIntToughness(); return value >= 0 ? op(value, operand) : false;
|
||||
default: return false;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean op(final int op1, final int op2) {
|
||||
switch (operator) {
|
||||
case EQUALS: return op1 == op2;
|
||||
case GREATER_THAN: return op1 > op2;
|
||||
case GT_OR_EQUAL: return op1 >= op2;
|
||||
case LESS_THAN: return op1 < op2;
|
||||
case LT_OR_EQUAL: return op1 <= op2;
|
||||
case NOT_EQUALS: return op1 != op2;
|
||||
default: return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class PredicateCoreType extends Predicate<CardRules> {
|
||||
private final CardCoreType operand;
|
||||
private final boolean shouldBeEqual;
|
||||
|
||||
@Override
|
||||
public boolean isTrue(final CardRules card) { return shouldBeEqual == card.getType().typeContains(operand); }
|
||||
|
||||
public PredicateCoreType(final CardCoreType type, final boolean wantEqual) {
|
||||
operand = type;
|
||||
shouldBeEqual = wantEqual;
|
||||
}
|
||||
}
|
||||
|
||||
private static class PredicateSuperType extends Predicate<CardRules> {
|
||||
private final CardSuperType operand;
|
||||
private final boolean shouldBeEqual;
|
||||
|
||||
@Override
|
||||
public boolean isTrue(final CardRules card) {
|
||||
return shouldBeEqual == card.getType().superTypeContains(operand);
|
||||
}
|
||||
|
||||
public PredicateSuperType(final CardSuperType type, final boolean wantEqual) {
|
||||
operand = type;
|
||||
shouldBeEqual = wantEqual;
|
||||
}
|
||||
}
|
||||
private static class PredicateLastesSetRarity extends Predicate<CardRules> {
|
||||
private final CardRarity operand;
|
||||
private final boolean shouldBeEqual;
|
||||
|
||||
@Override
|
||||
public boolean isTrue(final CardRules card) {
|
||||
return card.getRarityFromLatestSet().equals(operand);
|
||||
}
|
||||
|
||||
public PredicateLastesSetRarity(final CardRarity type, final boolean wantEqual) {
|
||||
operand = type;
|
||||
shouldBeEqual = wantEqual;
|
||||
}
|
||||
}
|
||||
|
||||
public static class Presets {
|
||||
public static final Predicate<CardRules> isCreature = coreType(true, CardCoreType.Creature);
|
||||
public static final Predicate<CardRules> isArtifact = coreType(true, CardCoreType.Artifact);
|
||||
public static final Predicate<CardRules> isLand = coreType(true, CardCoreType.Land);
|
||||
public static final Predicate<CardRules> isPlaneswalker = coreType(true, CardCoreType.Planeswalker);
|
||||
public static final Predicate<CardRules> isInstant = coreType(true, CardCoreType.Instant);
|
||||
public static final Predicate<CardRules> isSorcery = coreType(true, CardCoreType.Sorcery);
|
||||
public static final Predicate<CardRules> isEnchantment = coreType(true, CardCoreType.Enchantment);
|
||||
|
||||
public static final Predicate<CardRules> isNonLand = coreType(false, CardCoreType.Land);
|
||||
public static final Predicate<CardRules> isNonCreatureSpell = Predicate.compose(isCreature, PredicatesOp.NOR, isLand);
|
||||
|
||||
public static final Predicate<CardRules> isWhite = isColor(CardColor.WHITE);
|
||||
public static final Predicate<CardRules> isBlue = isColor(CardColor.BLUE);
|
||||
public static final Predicate<CardRules> isBlack = isColor(CardColor.BLACK);
|
||||
public static final Predicate<CardRules> isRed = isColor(CardColor.RED);
|
||||
public static final Predicate<CardRules> isGreen = isColor(CardColor.GREEN);
|
||||
public static final Predicate<CardRules> isColorless = hasCntColors((byte) 0);
|
||||
public static final Predicate<CardRules> isMulticolor = hasAtLeastCntColors((byte) 2);
|
||||
|
||||
// Think twice before using these, since rarity is a prop of printed card.
|
||||
public static final Predicate<CardRules> isInLatestSetCommon = rarityInCardsLatestSet(true, CardRarity.Common);
|
||||
public static final Predicate<CardRules> isInLatestSetUncommon = rarityInCardsLatestSet(true, CardRarity.Uncommon);
|
||||
public static final Predicate<CardRules> isInLatestSetRare = rarityInCardsLatestSet(true, CardRarity.Rare);
|
||||
public static final Predicate<CardRules> isInLatestSetMythicRare = rarityInCardsLatestSet(true, CardRarity.MythicRare);
|
||||
public static final Predicate<CardRules> isInLatestSetSpecial = rarityInCardsLatestSet(true, CardRarity.Special);
|
||||
}
|
||||
}
|
||||
}
|
||||
47
src/main/java/forge/card/CardSet.java
Normal file
47
src/main/java/forge/card/CardSet.java
Normal file
@@ -0,0 +1,47 @@
|
||||
package forge.card;
|
||||
|
||||
/**
|
||||
* <p>CardSet class.</p>
|
||||
*
|
||||
* @author Forge
|
||||
* @version $Id: CardSet.java 9708 2011-08-09 19:34:12Z jendave $
|
||||
*/
|
||||
public final class CardSet implements Comparable<CardSet> { // immutable
|
||||
private int index;
|
||||
private String code;
|
||||
private String code2;
|
||||
private String name;
|
||||
|
||||
public CardSet(final int index, final String name, final String code, final String code2) {
|
||||
this.code = code;
|
||||
this.code2 = code2;
|
||||
this.index = index;
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getName() { return name; }
|
||||
public String getCode() { return code; }
|
||||
public String getCode2() { return code2; }
|
||||
public int getIndex() { return index; }
|
||||
|
||||
@Override
|
||||
public int compareTo(final CardSet o) {
|
||||
if (o == null) { return 1; }
|
||||
return o.index - this.index;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return code.hashCode() * 17 + name.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) { return true; }
|
||||
if (obj == null) { return false; }
|
||||
if (getClass() != obj.getClass()) { return false; }
|
||||
|
||||
CardSet other = (CardSet) obj;
|
||||
return other.name.equals(this.name) && this.code.equals(other.code);
|
||||
}
|
||||
}
|
||||
6
src/main/java/forge/card/CardSuperType.java
Normal file
6
src/main/java/forge/card/CardSuperType.java
Normal file
@@ -0,0 +1,6 @@
|
||||
package forge.card;
|
||||
|
||||
public enum CardSuperType
|
||||
{
|
||||
Basic, Legendary, Show, Ongoing, World
|
||||
}
|
||||
113
src/main/java/forge/card/CardType.java
Normal file
113
src/main/java/forge/card/CardType.java
Normal file
@@ -0,0 +1,113 @@
|
||||
package forge.card;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.EnumSet;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
/**
|
||||
* <p>Immutable Card type. Can be build only from parsing a string.</p>
|
||||
*
|
||||
* @author Forge
|
||||
* @version $Id: CardType.java 9708 2011-08-09 19:34:12Z jendave $
|
||||
*/
|
||||
|
||||
public final class CardType implements Comparable<CardType> {
|
||||
private List<String> subType = new ArrayList<String>();
|
||||
private EnumSet<CardCoreType> coreType = EnumSet.noneOf(CardCoreType.class);
|
||||
private EnumSet<CardSuperType> superType = EnumSet.noneOf(CardSuperType.class);
|
||||
private String calculatedType = null; // since obj is immutable, this is calc'd once
|
||||
|
||||
// This will be useful for faster parses
|
||||
private static HashMap<String, CardCoreType> stringToCoreType = new HashMap<String, CardCoreType>();
|
||||
private static HashMap<String, CardSuperType> stringToSuperType = new HashMap<String, CardSuperType>();
|
||||
static {
|
||||
for (CardSuperType st : CardSuperType.values()) { stringToSuperType.put(st.name(), st); }
|
||||
for (CardCoreType ct : CardCoreType.values()) { stringToCoreType.put(ct.name(), ct); }
|
||||
}
|
||||
|
||||
private CardType() { } // use static ctors!
|
||||
|
||||
// TODO: Debug this code
|
||||
public static CardType parse(final String typeText) {
|
||||
// Most types and subtypes, except "Serra<72>s Realm" and "Bolas<61>s Meditation Realm" consist of only one word
|
||||
final char space = ' ';
|
||||
CardType result = new CardType();
|
||||
|
||||
int iTypeStart = 0;
|
||||
int iSpace = typeText.indexOf(space);
|
||||
boolean hasMoreTypes = typeText.length() > 0;
|
||||
while (hasMoreTypes) {
|
||||
String type = typeText.substring(iTypeStart, iSpace == -1 ? typeText.length() : iSpace );
|
||||
if (!isMultiwordType(type)) {
|
||||
iTypeStart = iSpace + 1;
|
||||
result.parseAndAdd(type);
|
||||
}
|
||||
hasMoreTypes = iSpace != -1;
|
||||
iSpace = typeText.indexOf(space, iSpace + 1);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private static boolean isMultiwordType(final String type) {
|
||||
final String[] multiWordTypes = {"Serra's Realm", "Bolas's Meditation Realm"};
|
||||
// no need to loop for only 2 exceptions!
|
||||
if (multiWordTypes[0].startsWith(type) && !multiWordTypes[0].equals(type)) { return true; }
|
||||
if (multiWordTypes[1].startsWith(type) && !multiWordTypes[1].equals(type)) { return true; }
|
||||
return false;
|
||||
}
|
||||
|
||||
private void parseAndAdd(final String type) {
|
||||
if ("-".equals(type)) { return; }
|
||||
|
||||
CardCoreType ct = stringToCoreType.get(type);
|
||||
if (ct != null) { coreType.add(ct); return; }
|
||||
|
||||
CardSuperType st = stringToSuperType.get(type);
|
||||
if (st != null) { superType.add(st); return; }
|
||||
|
||||
// If not recognized by super- and core- this must be subtype
|
||||
subType.add(type);
|
||||
}
|
||||
|
||||
public boolean subTypeContains(final String operand) { return subType.contains(operand); }
|
||||
public boolean typeContains(final CardCoreType operand) { return coreType.contains(operand); }
|
||||
public boolean superTypeContains(final CardSuperType operand) { return superType.contains(operand); }
|
||||
|
||||
public boolean isCreature() { return coreType.contains(CardCoreType.Creature); }
|
||||
public boolean isPlaneswalker() { return coreType.contains(CardCoreType.Planeswalker); }
|
||||
public boolean isLand() { return coreType.contains(CardCoreType.Land); }
|
||||
public boolean isArtifact() { return coreType.contains(CardCoreType.Artifact); }
|
||||
public boolean isInstant() { return coreType.contains(CardCoreType.Instant); }
|
||||
public boolean isSorcery() { return coreType.contains(CardCoreType.Sorcery); }
|
||||
public boolean isEnchantment() { return coreType.contains(CardCoreType.Enchantment); }
|
||||
|
||||
public String getTypesBeforeDash() {
|
||||
ArrayList<String> types = new ArrayList<String>();
|
||||
for (CardSuperType st : superType) { types.add(st.name()); }
|
||||
for (CardCoreType ct : coreType) { types.add(ct.name()); }
|
||||
return StringUtils.join(types, ' ');
|
||||
}
|
||||
|
||||
public String getTypesAfterDash() {
|
||||
return StringUtils.join(subType, " ");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
if (null == calculatedType) { calculatedType = toStringImpl(); }
|
||||
return calculatedType;
|
||||
}
|
||||
|
||||
private String toStringImpl() {
|
||||
if (subType.isEmpty()) { return getTypesBeforeDash(); }
|
||||
else { return String.format("%s - %s", getTypesBeforeDash(), getTypesAfterDash()); }
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(final CardType o) {
|
||||
return toString().compareTo(o.toString());
|
||||
}
|
||||
}
|
||||
|
||||
68
src/main/java/forge/card/MtgDataParser.java
Normal file
68
src/main/java/forge/card/MtgDataParser.java
Normal file
@@ -0,0 +1,68 @@
|
||||
package forge.card;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import javax.naming.OperationNotSupportedException;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
public final class MtgDataParser implements Iterator<CardRules> {
|
||||
|
||||
private Iterator<String> it;
|
||||
public MtgDataParser(final Iterable<String> data) {
|
||||
it = data.iterator();
|
||||
skipSetList();
|
||||
}
|
||||
|
||||
private boolean weHaveNext;
|
||||
private void skipSetList() {
|
||||
String nextLine = it.next();
|
||||
while (nextLine.length() > 0 && it.hasNext()) {
|
||||
nextLine = it.next();
|
||||
}
|
||||
weHaveNext = it.hasNext();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasNext() { return weHaveNext; }
|
||||
|
||||
private static final String[] emptyArray = new String[0]; // list.toArray() needs this =(
|
||||
|
||||
@Override
|
||||
public CardRules next() {
|
||||
if (!it.hasNext()) { weHaveNext = false; return null; }
|
||||
String name = it.next();
|
||||
if (!it.hasNext()) { weHaveNext = false; return null; }
|
||||
String manaCost = it.next();
|
||||
CardType type = null;
|
||||
if (manaCost.startsWith("{")) {
|
||||
if (!it.hasNext()) { weHaveNext = false; return null; }
|
||||
type = CardType.parse(it.next());
|
||||
} else { // Land?
|
||||
type = CardType.parse(manaCost);
|
||||
manaCost = null;
|
||||
}
|
||||
String ptOrLoyalty = null;
|
||||
if (type.isCreature() || type.isPlaneswalker()) {
|
||||
if (!it.hasNext()) { weHaveNext = false; return null; }
|
||||
ptOrLoyalty = it.next();
|
||||
}
|
||||
|
||||
List<String> strs = new ArrayList<String>();
|
||||
if (!it.hasNext()) { weHaveNext = false; return null; }
|
||||
String nextLine = it.next();
|
||||
while (StringUtils.isNotBlank(nextLine) && it.hasNext()) {
|
||||
strs.add(nextLine);
|
||||
nextLine = it.next();
|
||||
}
|
||||
String[] sets = strs.remove(strs.size() - 1).split(", ");
|
||||
|
||||
return new CardRules(name, type, manaCost, ptOrLoyalty, strs.toArray(emptyArray), sets);
|
||||
}
|
||||
|
||||
@Override public void remove() { }
|
||||
|
||||
|
||||
}
|
||||
@@ -101,6 +101,8 @@ public interface NewConstants {
|
||||
/** Constant <code>BOOSTERDATA="boosterdata"</code>. */
|
||||
String BOOSTERDATA = "boosterdata";
|
||||
|
||||
String MTG_DATA = "mtg-data";
|
||||
|
||||
/** Constant <code>IMAGE_BASE="image/base"</code>. */
|
||||
String IMAGE_BASE = "image/base";
|
||||
/** Constant <code>IMAGE_TOKEN="image/token"</code>. */
|
||||
|
||||
Reference in New Issue
Block a user