Refactored CardPrinted to support split cards

This commit is contained in:
Maxmtg
2013-02-20 13:18:53 +00:00
parent e68d9824c5
commit b98792858b
26 changed files with 578 additions and 1055 deletions

7
.gitattributes vendored
View File

@@ -13630,18 +13630,21 @@ src/main/java/forge/ImageCache.java svneol=native#text/plain
src/main/java/forge/Singletons.java svneol=native#text/plain src/main/java/forge/Singletons.java svneol=native#text/plain
src/main/java/forge/StaticEffect.java svneol=native#text/plain src/main/java/forge/StaticEffect.java svneol=native#text/plain
src/main/java/forge/StaticEffects.java svneol=native#text/plain src/main/java/forge/StaticEffects.java svneol=native#text/plain
src/main/java/forge/card/AggregationMethod.java -text
src/main/java/forge/card/BoosterData.java -text src/main/java/forge/card/BoosterData.java -text
src/main/java/forge/card/BoosterGenerator.java svneol=native#text/plain src/main/java/forge/card/BoosterGenerator.java svneol=native#text/plain
src/main/java/forge/card/CardAiHints.java -text
src/main/java/forge/card/CardBlock.java -text src/main/java/forge/card/CardBlock.java -text
src/main/java/forge/card/CardCharacteristics.java -text src/main/java/forge/card/CardCharacteristics.java -text
src/main/java/forge/card/CardCoreType.java -text src/main/java/forge/card/CardCoreType.java -text
src/main/java/forge/card/CardEdition.java -text src/main/java/forge/card/CardEdition.java -text
src/main/java/forge/card/CardFaceRules.java -text
src/main/java/forge/card/CardInSet.java -text src/main/java/forge/card/CardInSet.java -text
src/main/java/forge/card/CardRarity.java -text src/main/java/forge/card/CardRarity.java -text
src/main/java/forge/card/CardRuleCharacteristics.java -text
src/main/java/forge/card/CardRules.java -text src/main/java/forge/card/CardRules.java -text
src/main/java/forge/card/CardRulesPredicates.java -text src/main/java/forge/card/CardRulesPredicates.java -text
src/main/java/forge/card/CardRulesReader.java svneol=native#text/plain src/main/java/forge/card/CardRulesReader.java svneol=native#text/plain
src/main/java/forge/card/CardSplitType.java -text
src/main/java/forge/card/CardSuperType.java -text src/main/java/forge/card/CardSuperType.java -text
src/main/java/forge/card/CardType.java -text src/main/java/forge/card/CardType.java -text
src/main/java/forge/card/ColorSet.java -text src/main/java/forge/card/ColorSet.java -text
@@ -13650,9 +13653,9 @@ src/main/java/forge/card/EditionCollection.java svneol=native#text/plain
src/main/java/forge/card/EditionInfo.java svneol=native#text/plain src/main/java/forge/card/EditionInfo.java svneol=native#text/plain
src/main/java/forge/card/FatPackData.java -text src/main/java/forge/card/FatPackData.java -text
src/main/java/forge/card/FormatCollection.java -text src/main/java/forge/card/FormatCollection.java -text
src/main/java/forge/card/ICardCharacteristics.java -text
src/main/java/forge/card/MagicColor.java -text src/main/java/forge/card/MagicColor.java -text
src/main/java/forge/card/MetaSet.java -text src/main/java/forge/card/MetaSet.java -text
src/main/java/forge/card/MtgDataParser.java -text
src/main/java/forge/card/TriggerReplacementBase.java -text src/main/java/forge/card/TriggerReplacementBase.java -text
src/main/java/forge/card/UnOpenedMeta.java -text src/main/java/forge/card/UnOpenedMeta.java -text
src/main/java/forge/card/UnOpenedProduct.java -text src/main/java/forge/card/UnOpenedProduct.java -text

View File

@@ -2062,10 +2062,8 @@ public class Card extends GameEntity implements Comparable<Card> {
// Vanguard Modifiers // Vanguard Modifiers
if (this.isType("Vanguard")) { if (this.isType("Vanguard")) {
final CardPrinted avatar = CardDb.getCard(this); final CardPrinted avatar = CardDb.getCard(this);
sb.append("Hand Modifier: "); sb.append("Hand Modifier: ").append(avatar.getRules().getHand());
sb.append(avatar.getRules().getHand()); sb.append("\r\nLife Modifier: ").append(avatar.getRules().getLife());
sb.append("\r\nLife Modifier: ");
sb.append(avatar.getRules().getLife());
sb.append("\r\n\r\n"); sb.append("\r\n\r\n");
} }
sb.append(this.getAbilityText()); sb.append(this.getAbilityText());

View File

@@ -0,0 +1,7 @@
package forge.card;
public enum AggregationMethod {
USE_ACTIVE_FACE,
USE_PRIMARY_FACE,
AGGREGATE;
}

View File

@@ -301,11 +301,8 @@ public class BoosterGenerator {
} }
private void addToRarity(final CardPrinted c) { private void addToRarity(final CardPrinted c) {
if (c.getRules().isAltState()) {
return;
}
Map<CardRarity, List<CardPrinted>> targetList = c.getRules().isDoubleFaced() ? twoFacedByRarity : singleFacedByRarity; Map<CardRarity, List<CardPrinted>> targetList = c.getRules().getSplitType() == CardSplitType.Transform ? twoFacedByRarity : singleFacedByRarity;
targetList.get(c.getRarity()).add(c); targetList.get(c.getRarity()).add(c);
if (!c.getRules().getType().isBasicLand()) { if (!c.getRules().getType().isBasicLand()) {

View File

@@ -0,0 +1,74 @@
package forge.card;
/**
* TODO: Write javadoc for this type.
*
*/
public class CardAiHints {
private final boolean isRemovedFromAIDecks;
private final boolean isRemovedFromRandomDecks;
private final DeckHints deckHints;
private final DeckHints deckNeeds;
public CardAiHints(boolean remAi, boolean remRandom, DeckHints dh, DeckHints dn) {
isRemovedFromAIDecks = remAi;
isRemovedFromRandomDecks = remRandom;
deckHints = dh;
deckNeeds = dn;
}
/**
* Gets the rem ai decks.
*
* @return the rem ai decks
*/
public boolean getRemAIDecks() {
return this.isRemovedFromAIDecks;
}
/**
* Gets the rem random decks.
*
* @return the rem random decks
*/
public boolean getRemRandomDecks() {
return this.isRemovedFromRandomDecks;
}
/**
* @return the deckHints
*/
public DeckHints getDeckHints() {
return deckHints;
}
/**
* @return the deckHints
*/
public DeckHints getDeckNeeds() {
return deckNeeds;
}
/**
* Gets the ai status comparable.
*
* @return the ai status comparable
*/
public Integer getAiStatusComparable() {
if (this.isRemovedFromAIDecks && this.isRemovedFromRandomDecks) {
return Integer.valueOf(3);
} else if (this.isRemovedFromAIDecks) {
return Integer.valueOf(4);
} else if (this.isRemovedFromRandomDecks) {
return Integer.valueOf(2);
} else {
return Integer.valueOf(1);
}
}
}

View File

@@ -0,0 +1,102 @@
package forge.card;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Map.Entry;
import java.util.TreeMap;
import org.apache.commons.lang3.StringUtils;
import forge.card.mana.ManaCost;
//
// DO NOT AUTOFORMAT / CHECKSTYLE THIS FILE
//
/**
* TODO: Write javadoc for this type.
*
*/
public class CardFaceRules implements ICardCharacteristics {
private final String name;
private CardType type = null;
private ManaCost manaCost = ManaCost.NO_COST;
private ColorSet color = null;
private String oracleText = null;
private int iPower = -1;
private int iToughness = -1;
private String power = null;
private String toughness = null;
private int initialLoyalty = 0;
private final List<String> keywords = new ArrayList<String>();
// these implement ICardCharacteristics
@Override public String getOracleText() { return oracleText; }
@Override public int getIntPower() { return iPower; }
@Override public int getIntToughness() { return iToughness; }
@Override public String getPower() { return power; }
@Override public String getToughness() { return toughness; }
@Override public int getInitialLoyalty() { return initialLoyalty; }
@Override public final String getName() { return this.name; }
@Override public final CardType getType() { return this.type; }
@Override public final ManaCost getManaCost() { return this.manaCost; }
@Override public final ColorSet getColor() { return this.color; }
@Override public Iterable<String> getKeywords() { return keywords; }
// setters to allow parsers supply values here
public CardFaceRules(String name0) { this.name = name0; if ( StringUtils.isBlank(name0) ) throw new RuntimeException("Card name is empty"); }
public void setType(CardType type0) { this.type = type0; }
public void setManaCost(ManaCost manaCost0) { this.manaCost = manaCost0; }
public void setColor(ColorSet color0) { this.color = color0; }
public void setOracleText(String text) { this.oracleText = text; }
public void addKeyword(String value) { this.keywords.add(value); }
public void setInitialLoaylty(int value) { this.initialLoyalty = value; }
public Map<String, CardInSet> getSetsData() { return this.setsPrinted; } // reader will add sets here
public void setPtText(String value) {
final int slashPos = value == null ? -1 : value.indexOf('/');
if (slashPos == -1) {
throw new RuntimeException(String.format("Creature '%s' has bad p/t stats", this.getName()));
}
this.power = value.substring(0, slashPos);
this.toughness = value.substring(slashPos + 1);
this.iPower = StringUtils.isNumeric(this.power) ? Integer.parseInt(this.power) : 0;
this.iToughness = StringUtils.isNumeric(this.toughness) ? Integer.parseInt(this.toughness) : 0;
}
public void calculateColor() { // Most scripts do not specify color explicitly
if ( oracleText == null ) System.err.println(name + " has no Oracle text");
if ( manaCost == null && color == null ) System.err.println(name + " has neither ManaCost nor Color");
if ( color == null ) color = ColorSet.fromManaCost(manaCost);
}
// This should not be here
private final Map<String, CardInSet> setsPrinted = new TreeMap<String, CardInSet>(String.CASE_INSENSITIVE_ORDER);
@Override public Set<Entry<String, CardInSet>> getSetsPrinted() { return this.setsPrinted.entrySet(); }
@Override public CardInSet getEditionInfo(final String setCode) {
final CardInSet result = this.setsPrinted.get(setCode);
if (result != null) {
return result;
}
throw new RuntimeException(String.format("Card '%s' was never printed in set '%s'", this.getName(), setCode));
}
}

View File

@@ -1,228 +0,0 @@
/*
* Forge: Play Magic: the Gathering.
* Copyright (C) 2011 Forge Team
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package forge.card;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import forge.card.mana.ManaCost;
/**
* TODO: Write javadoc for this type.
*
*/
public class CardRuleCharacteristics {
private String cardName = null;
private CardType cardType = null;
private ManaCost manaCost = ManaCost.NO_COST;
private ColorSet color = null;
private String ptLine = null;
private String oracleText = null;
private Map<String, CardInSet> setsData = new TreeMap<String, CardInSet>();
private String dlUrl;
private DeckHints deckHints;
private DeckHints deckNeeds;
private final List<String> keywords = new ArrayList<String>();
/**
* Gets the card name.
*
* @return the cardName
*/
public final String getCardName() {
return this.cardName;
}
/**
* Sets the card name.
*
* @param cardName0
* the cardName to set
*/
public final void setCardName(final String cardName0) {
this.cardName = cardName0;
}
/**
* Gets the card type.
*
* @return the cardType
*/
public final CardType getCardType() {
return this.cardType;
}
/**
* Sets the card type.
*
* @param cardType0
* the cardType to set
*/
public final void setCardType(final CardType cardType0) {
this.cardType = cardType0;
}
/**
* Gets the mana cost.
*
* @return the manaCost
*/
public final ManaCost getManaCost() {
return this.manaCost;
}
/**
* Sets the mana cost.
*
* @param manaCost0
* the manaCost to set
*/
public final void setManaCost(final ManaCost manaCost0) {
this.manaCost = manaCost0;
this.color = ColorSet.fromManaCost(this.manaCost);
}
/**
* Gets the color.
*
* @return the color
*/
public final ColorSet getColor() {
return this.color;
}
/**
* Sets the color.
*
* @param color0
* the color to set
*/
public final void setColor(final ColorSet color0) {
this.color = color0;
}
/**
* Gets the pt line.
*
* @return the ptLine
*/
public final String getPtLine() {
return this.ptLine;
}
/**
* Sets the pt line.
*
* @param ptLine0
* the ptLine to set
*/
public final void setPtLine(final String ptLine0) {
this.ptLine = ptLine0;
}
/**
* Gets the card rules.
*
* @return the cardRules
*/
public final String getOracleText() {
return this.oracleText;
}
/**
* Sets the card rules.
*
* @param cardRules0
* the cardRules to set
*/
public final void setCardRules(final String cardRules0) {
this.oracleText = cardRules0;
}
/**
* Gets the sets data.
*
* @return the setsData
*/
public final Map<String, CardInSet> getSetsData() {
return this.setsData;
}
/**
* Sets the sets data.
*
* @param setsData0
* the setsData to set
*/
public final void setSetsData(final Map<String, CardInSet> setsData0) {
this.setsData = setsData0;
}
public String getDlUrl() {
return dlUrl;
}
public void setDlUrl(String dlUrl) {
this.dlUrl = dlUrl;
}
/**
* Set the deck hints.
*
* @param valueAfterKey
*/
public void setDeckHints(String valueAfterKey) {
deckHints = new DeckHints(valueAfterKey);
}
public DeckHints getDeckHints() {
return deckHints;
}
/**
* Set the deck hints.
*
* @param valueAfterKey
*/
public void setDeckNeeds(String valueAfterKey) {
deckNeeds = new DeckHints(valueAfterKey);
}
public DeckHints getDeckNeeds() {
return deckNeeds;
}
/**
* @return the keywords
*/
public List<String> getKeywords() {
return keywords;
}
/**
* Add keyword.
*
* @param keyword
*/
public void addKeyword(String keyword) {
this.keywords.add(keyword);
}
}

View File

@@ -21,9 +21,7 @@ import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Map.Entry; import java.util.Map.Entry;
import java.util.Set; import com.google.common.collect.Lists;
import org.apache.commons.lang3.StringUtils;
import forge.card.mana.ManaCost; import forge.card.mana.ManaCost;
@@ -38,264 +36,27 @@ import forge.card.mana.ManaCost;
* @author Forge * @author Forge
* @version $Id: CardRules.java 9708 2011-08-09 19:34:12Z jendave $ * @version $Id: CardRules.java 9708 2011-08-09 19:34:12Z jendave $
*/ */
public final class CardRules { public final class CardRules implements ICardCharacteristics {
private final CardRuleCharacteristics characteristics; private final CardSplitType splitType;
private final ICardCharacteristics mainPart;
private int iPower = -1; private final ICardCharacteristics otherPart;
private int iToughness = -1;
private String power = null; private CardAiHints aiHints;
private String toughness = null;
private String loyalty = null;
//Vanguard avatar modifiers
private Integer life = null;
private Integer hand = null;
Map<String, CardInSet> setsPrinted = null; Map<String, CardInSet> setsPrinted = null;
private Iterable<String> forgeScript;
boolean isRemovedFromAIDecks = false;
boolean isRemovedFromRandomDecks = false;
private final CardRules slavePart;
private final boolean hasOtherFace; public CardRules(ICardCharacteristics[] faces, CardSplitType altMode, CardAiHints cah, Iterable<String> script) {
splitType = altMode;
private List<String> originalScript; mainPart = faces[0];
otherPart = faces[1];
// Ctor and builders are needed here aiHints = cah;
/** forgeScript = Lists.newArrayList(script);
* Gets the name.
*
* @return the name
*/
public String getName() {
return this.characteristics.getCardName();
} }
/**
* Gets the type.
*
* @return the type
*/
public CardType getType() {
return this.characteristics.getCardType();
}
/**
* Gets the mana cost.
*
* @return the mana cost
*/
public ManaCost getManaCost() {
return this.characteristics.getManaCost();
}
/**
* Gets the color.
*
* @return the color
*/
public ColorSet getColor() {
return this.characteristics.getColor();
}
/**
* Gets the rules.
*
* @return the rules
*/
public String getOracleText() {
return this.characteristics.getOracleText();
}
/**
*
* Gets Slave Part.
*
* @return CardRules
*/
public CardRules getSlavePart() {
return this.slavePart;
}
/**
* Gets the sets printed.
*
* @return the sets printed
*/
public Set<Entry<String, CardInSet>> getSetsPrinted() {
return this.characteristics.getSetsData().entrySet();
}
/**
* Gets the power.
*
* @return the power
*/
public String getPower() {
return this.power;
}
/**
* Gets the int power.
*
* @return the int power
*/
public int getIntPower() {
return this.iPower;
}
/**
* Gets the toughness.
*
* @return the toughness
*/
public String getToughness() {
return this.toughness;
}
/**
* Gets the int toughness.
*
* @return the int toughness
*/
public int getIntToughness() {
return this.iToughness;
}
/**
* Gets the loyalty.
*
* @return the loyalty
*/
public String getLoyalty() {
return this.loyalty;
}
/**
* Gets the rem ai decks.
*
* @return the rem ai decks
*/
public boolean getRemAIDecks() {
return this.isRemovedFromAIDecks;
}
/**
* Gets the rem random decks.
*
* @return the rem random decks
*/
public boolean getRemRandomDecks() {
return this.isRemovedFromRandomDecks;
}
/**
* Gets the p tor loyalty.
*
* @return the p tor loyalty
*/
public String getPTorLoyalty() {
if (this.getType().isCreature()) {
return this.power + "/" + this.toughness;
}
if (this.getType().isPlaneswalker()) {
return this.loyalty;
}
return "";
}
/**
* Checks if is alt state.
*
* @return true, if is alt state
*/
public boolean isAltState() {
return this.isDoubleFaced() && (this.slavePart == null);
}
/**
* Checks if is double faced.
*
* @return true, if is double faced
*/
public boolean isDoubleFaced() {
return this.hasOtherFace;
}
/**
* Instantiates a new card rules.
*
* @param chars
* the chars
* @param isDoubleFacedCard
* the is double faced card
* @param otherPart
* the otherPart
* @param removedFromRandomDecks
* the removed from random decks
* @param removedFromAIDecks
* the removed from ai decks
*/
public CardRules(final CardRuleCharacteristics chars, List<String> forgeScript, final boolean isDoubleFacedCard,
final CardRules otherPart, final boolean removedFromRandomDecks, final boolean removedFromAIDecks) {
this.characteristics = chars;
this.slavePart = otherPart;
this.hasOtherFace = isDoubleFacedCard;
this.isRemovedFromAIDecks = removedFromAIDecks;
this.isRemovedFromRandomDecks = removedFromRandomDecks;
this.originalScript = forgeScript == null ? null : new ArrayList<String>(forgeScript);
// System.out.println(cardName);
if (this.getType().isCreature()) {
final int slashPos = this.characteristics.getPtLine() == null ? -1 : this.characteristics.getPtLine()
.indexOf('/');
if (slashPos == -1) {
throw new RuntimeException(String.format("Creature '%s' has bad p/t stats", this.getName()));
}
this.power = this.characteristics.getPtLine().substring(0, slashPos);
this.toughness = this.characteristics.getPtLine().substring(slashPos + 1,
this.characteristics.getPtLine().length());
this.iPower = StringUtils.isNumeric(this.power) ? Integer.parseInt(this.power) : 0;
this.iToughness = StringUtils.isNumeric(this.toughness) ? Integer.parseInt(this.toughness) : 0;
} else if (this.getType().isPlaneswalker()) {
this.loyalty = this.characteristics.getPtLine();
} else if (this.getType().isVanguard()) {
String pt = this.characteristics.getPtLine();
final int slashPos = this.characteristics.getPtLine() == null ? -1 : this.characteristics.getPtLine()
.indexOf('/');
if (slashPos == -1) {
throw new RuntimeException(String.format("Vanguard '%s' has bad hand/life stats", this.getName()));
}
this.hand = Integer.parseInt(pt.substring(0, pt.indexOf('/')).replace("+", ""));
this.life = Integer.parseInt(pt.substring(pt.indexOf('/') + 1).replace("+", ""));
}
if (this.characteristics.getSetsData().isEmpty()) {
this.characteristics.getSetsData().put("???", new CardInSet(CardRarity.Unknown, 1, null));
}
this.setsPrinted = this.characteristics.getSetsData();
}
/**
* Rules contain.
*
* @param text
* the text
* @return true, if successful
*/
public boolean rulesContain(final String text) {
if (this.characteristics.getOracleText() == null) {
return false;
}
if (StringUtils.containsIgnoreCase(this.characteristics.getOracleText(), text)) {
return true;
}
return false;
}
/** /**
* Gets the latest set printed. * Gets the latest set printed.
@@ -311,21 +72,7 @@ public final class CardRules {
return lastSet; return lastSet;
} }
/**
* Gets the sets the info.
*
* @param setCode
* the set code
* @return the sets the info
*/
public CardInSet getEditionInfo(final String setCode) {
final CardInSet result = this.setsPrinted.get(setCode);
if (result != null) {
return result;
}
throw new RuntimeException(String.format("Card '%s' was never printed in set '%s'", this.getName(), setCode));
}
/** /**
* Gets the rarity from latest set. * Gets the rarity from latest set.
@@ -337,88 +84,145 @@ public final class CardRules {
return cis.getRarity(); return cis.getRarity();
} }
/**
* Gets the ai status.
*
* @return the ai status
*/
public String getAiStatus() {
return this.isRemovedFromAIDecks ? (this.isRemovedFromRandomDecks ? "AI ?" : "AI")
: (this.isRemovedFromRandomDecks ? "?" : "");
}
/**
* Gets the ai status comparable.
*
* @return the ai status comparable
*/
public Integer getAiStatusComparable() {
if (this.isRemovedFromAIDecks && this.isRemovedFromRandomDecks) {
return Integer.valueOf(3);
} else if (this.isRemovedFromAIDecks) {
return Integer.valueOf(4);
} else if (this.isRemovedFromRandomDecks) {
return Integer.valueOf(2);
} else {
return Integer.valueOf(1);
}
}
/** /**
* TODO: Write javadoc for this method. * TODO: Write javadoc for this method.
* @return * @return
*/ */
public Iterable<String> getCardScript() { public Iterable<String> getForgeScript() {
return originalScript; return forgeScript;
} }
/**
* TODO: Write javadoc for this method.
* @return
*/
public String getPictureUrl() {
return characteristics.getDlUrl();
}
/**
* @return the deckHints
*/
public DeckHints getDeckHints() {
return characteristics.getDeckHints();
}
/**
* @return the deckHints
*/
public DeckHints getDeckNeeds() {
return characteristics.getDeckNeeds();
}
/**
* @return the keywords
*/
public List<String> getKeywords() {
return characteristics.getKeywords();
}
/**
* @return the hand
*/
public Integer getHand() {
return hand;
}
/**
* @return the life
*/
public Integer getLife() {
return life;
}
public boolean isTraditional() { public boolean isTraditional() {
return !(getType().isVanguard() || getType().isScheme() || getType().isPlane() || getType().isPhenomenon()); return !(getType().isVanguard() || getType().isScheme() || getType().isPlane() || getType().isPhenomenon());
} }
/**
* @return the splitType
*/
public CardSplitType getSplitType() {
return splitType;
}
public ICardCharacteristics getMainPart() {
// TODO Auto-generated method stub
return mainPart;
}
public ICardCharacteristics getOtherPart() {
return otherPart;
}
public String getName() {
switch(splitType.getAggregationMethod()) {
case AGGREGATE:
return mainPart.getName() + " // " + otherPart.getName();
default:
return mainPart.getName();
}
}
public CardAiHints getAiHints() {
return aiHints;
}
@Override
public CardType getType() {
switch(splitType.getAggregationMethod()) {
case AGGREGATE: // no cards currently have different types
return CardType.combine(mainPart.getType(), otherPart.getType());
default:
return mainPart.getType();
}
}
@Override
public ManaCost getManaCost() {
switch(splitType.getAggregationMethod()) {
case AGGREGATE:
return ManaCost.combine(mainPart.getManaCost(), otherPart.getManaCost());
default:
return mainPart.getManaCost();
}
}
@Override
public ColorSet getColor() {
switch(splitType.getAggregationMethod()) {
case AGGREGATE:
return ColorSet.fromMask(mainPart.getColor().getColor() | otherPart.getColor().getColor());
default:
return mainPart.getColor();
}
}
@Override public int getIntPower() { return mainPart.getIntPower(); }
@Override public int getIntToughness() { return mainPart.getIntToughness(); }
@Override public String getPower() { return mainPart.getPower(); }
@Override public String getToughness() { return mainPart.getToughness(); }
@Override public int getInitialLoyalty() { return mainPart.getInitialLoyalty(); }
@Override
public String getOracleText() {
switch(splitType.getAggregationMethod()) {
case AGGREGATE:
return mainPart.getOracleText() + "\r\n\r\n" + otherPart.getOracleText();
default:
return mainPart.getOracleText();
}
}
@Override
public Iterable<String> getKeywords() {
switch(splitType.getAggregationMethod()) {
case AGGREGATE:
List<String> res = new ArrayList<String>();
for(String ka : mainPart.getKeywords())
res.add(ka);
for(String kb : otherPart.getKeywords())
res.add(kb);
return res;
default:
return mainPart.getKeywords();
}
}
public Iterable<Entry<String, CardInSet>> getSetsPrinted() { return mainPart.getSetsPrinted(); }
public CardInSet getEditionInfo(final String setCode) { return mainPart.getEditionInfo(setCode); }
// vanguard card fields, they don't use sides.
private int deltaHand;
private int deltaLife;
public int getHand() { return deltaHand; }
public int getLife() { return deltaLife; }
public void setVanguardProperties(String pt) {
final int slashPos = pt == null ? -1 : pt.indexOf('/');
if (slashPos == -1) {
throw new RuntimeException(String.format("Vanguard '%s' has bad hand/life stats", this.getName()));
}
this.deltaHand = Integer.parseInt(pt.substring(0, pt.indexOf('/')).replace("+", ""));
this.deltaLife = Integer.parseInt(pt.substring(pt.indexOf('/') + 1).replace("+", ""));
}
// Downloadable image
private String dlUrl;
private String dlUrlOtherSide;
public String getPictureUrl() { return dlUrl; }
public String getPictureOtherSideUrl() { return dlUrlOtherSide; }
public void setDlUrls(String[] dlUrls) { this.dlUrl = dlUrls[0]; this.dlUrlOtherSide = dlUrls[1]; }
} }

View File

@@ -5,6 +5,7 @@ import java.util.List;
import com.google.common.base.Predicate; import com.google.common.base.Predicate;
import com.google.common.base.Predicates; import com.google.common.base.Predicates;
import com.google.common.collect.Iterables;
import forge.util.ComparableOp; import forge.util.ComparableOp;
import forge.util.PredicateString; import forge.util.PredicateString;
@@ -19,7 +20,7 @@ public final class CardRulesPredicates {
public static final Predicate<CardRules> IS_KEPT_IN_AI_DECKS = new Predicate<CardRules>() { public static final Predicate<CardRules> IS_KEPT_IN_AI_DECKS = new Predicate<CardRules>() {
@Override @Override
public boolean apply(final CardRules card) { public boolean apply(final CardRules card) {
return !card.isRemovedFromAIDecks; return !card.getAiHints().getRemAIDecks();
} }
}; };
@@ -27,7 +28,7 @@ public final class CardRulesPredicates {
public static final Predicate<CardRules> IS_KEPT_IN_RANDOM_DECKS = new Predicate<CardRules>() { public static final Predicate<CardRules> IS_KEPT_IN_RANDOM_DECKS = new Predicate<CardRules>() {
@Override @Override
public boolean apply(final CardRules card) { public boolean apply(final CardRules card) {
return !card.isRemovedFromRandomDecks; return !card.getAiHints().getRemRandomDecks();
} }
}; };
@@ -81,7 +82,7 @@ public final class CardRulesPredicates {
* @return the predicate * @return the predicate
*/ */
public static Predicate<CardRules> rules(final PredicateString.StringOp op, final String what) { public static Predicate<CardRules> rules(final PredicateString.StringOp op, final String what) {
return new LeafString(LeafString.CardField.RULES, op, what); return new LeafString(LeafString.CardField.ORACLE_TEXT, op, what);
} }
/** /**
@@ -145,7 +146,7 @@ public final class CardRulesPredicates {
return new Predicate<CardRules>() { return new Predicate<CardRules>() {
@Override @Override
public boolean apply(final CardRules card) { public boolean apply(final CardRules card) {
return card.getKeywords().contains(keyword); return Iterables.contains(card.getKeywords(), keyword);
} }
}; };
} }
@@ -291,7 +292,7 @@ public final class CardRulesPredicates {
private static class LeafString extends PredicateString<CardRules> { private static class LeafString extends PredicateString<CardRules> {
public enum CardField { public enum CardField {
RULES, NAME, SUBTYPE, JOINED_TYPE ORACLE_TEXT, NAME, SUBTYPE, JOINED_TYPE
} }
private final String operand; private final String operand;
@@ -306,9 +307,9 @@ public final class CardRulesPredicates {
case SUBTYPE: case SUBTYPE:
shouldContain = (this.getOperator() == StringOp.CONTAINS) || (this.getOperator() == StringOp.EQUALS); shouldContain = (this.getOperator() == StringOp.CONTAINS) || (this.getOperator() == StringOp.EQUALS);
return shouldContain == card.getType().subTypeContains(this.operand); return shouldContain == card.getType().subTypeContains(this.operand);
case RULES: case ORACLE_TEXT:
shouldContain = (this.getOperator() == StringOp.CONTAINS) || (this.getOperator() == StringOp.EQUALS); shouldContain = (this.getOperator() == StringOp.CONTAINS) || (this.getOperator() == StringOp.EQUALS);
return shouldContain == card.rulesContain(this.operand); return shouldContain == card.getOracleText().contains(this.operand);
case JOINED_TYPE: case JOINED_TYPE:
return this.op(card.getType().toString(), this.operand); return this.op(card.getType().toString(), this.operand);
default: default:

View File

@@ -20,6 +20,7 @@ package forge.card;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import org.apache.commons.lang3.StringUtils;
import forge.card.mana.ManaCostShard; import forge.card.mana.ManaCostShard;
import forge.card.mana.IParserManaCost; import forge.card.mana.IParserManaCost;
@@ -37,13 +38,22 @@ import forge.card.mana.ManaCost;
*/ */
public class CardRulesReader { public class CardRulesReader {
private CardRuleCharacteristics[] characteristics = new CardRuleCharacteristics[] { new CardRuleCharacteristics(), // fields to build
null }; private List<String> originalScript = new ArrayList<String>();
private int curCharacteristics = 0;
private CardFaceRules[] faces = new CardFaceRules[] { null, null };
private String[] pictureUrl = new String[] { null, null };
private int curFace = 0;
private CardSplitType altMode;
private String handLife = null;
// fields to build CardAiHints
private boolean removedFromAIDecks = false; private boolean removedFromAIDecks = false;
private boolean removedFromRandomDecks = false; private boolean removedFromRandomDecks = false;
private List<String> originalScript = new ArrayList<String>(); private DeckHints hints = null;
private DeckHints needs = null;
// Reset all fields to parse next card (to avoid allocating new // Reset all fields to parse next card (to avoid allocating new
// CardRulesReader N times) // CardRulesReader N times)
@@ -51,13 +61,21 @@ public class CardRulesReader {
* Reset. * Reset.
*/ */
public final void reset() { public final void reset() {
this.characteristics = new CardRuleCharacteristics[] { new CardRuleCharacteristics(), null }; originalScript.clear();
this.curCharacteristics = 0;
this.curFace = 0;
this.faces[0] = null;
this.faces[1] = null;
this.pictureUrl[0] = null;
this.pictureUrl[1] = null;
this.handLife = null;
this.altMode = CardSplitType.None;
this.removedFromAIDecks = false; this.removedFromAIDecks = false;
this.removedFromRandomDecks = false; this.removedFromRandomDecks = false;
originalScript.clear(); this.needs = null;
// this.isDoubleFacedCard = false; this.hints = null;
// this.isFlipCard = false;
} }
/** /**
@@ -66,12 +84,14 @@ public class CardRulesReader {
* @return the card * @return the card
*/ */
public final CardRules getCard() { public final CardRules getCard() {
final boolean hasOtherPart = this.characteristics[1] != null; CardAiHints cah = new CardAiHints(removedFromAIDecks, removedFromRandomDecks, hints, needs );
final CardRules otherPart = hasOtherPart ? new CardRules(this.characteristics[1], null, true, null, faces[0].calculateColor();
this.removedFromRandomDecks, this.removedFromAIDecks) : null; if ( null != faces[1] ) faces[1].calculateColor();
final CardRules result = new CardRules(faces, altMode, cah, originalScript);
return new CardRules(this.characteristics[0], originalScript, hasOtherPart, otherPart, this.removedFromRandomDecks, result.setDlUrls(pictureUrl);
this.removedFromAIDecks); if ( StringUtils.isNotBlank(handLife))
result.setVanguardProperties(handLife);
return result;
} }
/** /**
@@ -83,103 +103,106 @@ public class CardRulesReader {
public final void parseLine(final String line) { public final void parseLine(final String line) {
originalScript.add(line); originalScript.add(line);
int colonPos = line.indexOf(':');
String key = colonPos > 0 ? line.substring(0, colonPos) : line;
String value = colonPos > 0 ? line.substring(1+colonPos).trim() : null;
switch(line.charAt(0)) {
switch(key.charAt(0)) {
case 'A': case 'A':
if (line.startsWith("AlternateMode:")) { if ("AlternateMode".equals(key)) {
// this.isDoubleFacedCard = "DoubleFaced".equalsIgnoreCase(CardRulesReader.getValueAfterKey(line, "AlternateMode:")); //System.out.println(faces[curFace].getName());
// this.isFlipCard = "Flip".equalsIgnoreCase(CardRulesReader.getValueAfterKey(line, "AlternateMode:")); this.altMode = CardSplitType.smartValueOf(value);
} else if (line.equals("ALTERNATE")) { } else if ("ALTERNATE".equals(key)) {
this.characteristics[1] = new CardRuleCharacteristics(); this.curFace = 1;
this.curCharacteristics = 1;
} }
break; break;
case 'C': case 'C':
if (line.startsWith("Colors:")) { if ("Colors".equals(key)) {
// This is forge.card.CardColor not forge.CardColor. // This is forge.card.CardColor not forge.CardColor.
// Why do we have two classes with the same name? // Why do we have two classes with the same name?
final String value = line.substring("Colors:".length());
ColorSet newCol = ColorSet.fromNames(value.split(",")); ColorSet newCol = ColorSet.fromNames(value.split(","));
this.characteristics[this.curCharacteristics].setColor(newCol); this.faces[this.curFace].setColor(newCol);
} }
break; break;
case 'D': case 'D':
if (line.startsWith("DeckHints:")) { if ("DeckHints".equals(key)) {
this.characteristics[this.curCharacteristics].setDeckHints(CardRulesReader.getValueAfterKey(line, "DeckHints:")); hints = new DeckHints(value);
} else if (line.startsWith("DeckNeeds:")) { } else if ("DeckNeeds".equals(key)) {
this.characteristics[this.curCharacteristics].setDeckNeeds(CardRulesReader.getValueAfterKey(line, "DeckNeeds:")); needs = new DeckHints(value);
} }
break; break;
case 'H': case 'H':
if (line.startsWith("HandLifeModifier:")) { if ("HandLifeModifier".equals(key)) {
this.characteristics[this.curCharacteristics].setPtLine(CardRulesReader.getValueAfterKey(line, "HandLifeModifier:")); handLife = value;
} }
break; break;
case 'K': case 'K':
if (line.startsWith("K:")) { if ("K".equals(key)) {
final String value = line.substring(2); this.faces[this.curFace].addKeyword(value);
this.characteristics[this.curCharacteristics].addKeyword(value);
} }
break; break;
case 'L': case 'L':
if (line.startsWith("Loyalty:")) { if ("Loyalty".equals(key)) {
this.characteristics[this.curCharacteristics].setPtLine(CardRulesReader.getValueAfterKey(line, "Loyalty:")); this.faces[this.curFace].setInitialLoaylty(Integer.valueOf(value));
} }
break; break;
case 'M': case 'M':
if (line.startsWith("ManaCost:")) { if ("ManaCost".equals(key)) {
final String sCost = CardRulesReader.getValueAfterKey(line, "ManaCost:"); this.faces[this.curFace].setManaCost("no cost".equals(value) ? ManaCost.NO_COST
this.characteristics[this.curCharacteristics].setManaCost("no cost".equals(sCost) ? ManaCost.NO_COST : new ManaCost(new ParserCardnameTxtManaCost(value)));
: new ManaCost(new ParserCardnameTxtManaCost(sCost)));
} }
break;
case 'N': case 'N':
if (line.startsWith("Name:")) { if ("Name".equals(key)) {
this.characteristics[this.curCharacteristics].setCardName(CardRulesReader.getValueAfterKey(line, "Name:")); this.faces[this.curFace] = new CardFaceRules(value);
if ((this.characteristics[this.curCharacteristics].getCardName() == null)
|| this.characteristics[this.curCharacteristics].getCardName().isEmpty()) {
throw new RuntimeException("Card name is empty");
}
} }
break; break;
case 'O': case 'O':
if (line.startsWith("Oracle:")) { if ("Oracle".equals(key)) {
this.characteristics[this.curCharacteristics].setCardRules(CardRulesReader this.faces[this.curFace].setOracleText(value);
.getValueAfterKey(line, "Oracle:"));
} }
break; break;
case 'P': case 'P':
if (line.startsWith("PT:")) { if ("PT".equals(key)) {
this.characteristics[this.curCharacteristics].setPtLine(CardRulesReader.getValueAfterKey(line, "PT:")); this.faces[this.curFace].setPtText(value);
} }
break; break;
case 'S': case 'S':
if (line.startsWith("SVar:RemAIDeck:")) { if ( "SVar".equals(key) ) {
this.removedFromAIDecks = "True".equalsIgnoreCase(CardRulesReader.getValueAfterKey(line, "SVar:RemAIDeck:")); if ( null == value ) throw new IllegalArgumentException("SVar has no variable name");
} else if (line.startsWith("SVar:RemRandomDeck:")) {
this.removedFromRandomDecks = "True".equalsIgnoreCase(CardRulesReader.getValueAfterKey(line, "SVar:RemRandomDeck:")); colonPos = value.indexOf(':');
} else if (line.startsWith("SVar:Picture:")) { String variable = colonPos > 0 ? value.substring(0, colonPos) : value;
this.characteristics[this.curCharacteristics].setDlUrl(CardRulesReader.getValueAfterKey(line, "SVar:Picture:")); value = colonPos > 0 ? value.substring(1+colonPos) : null;
if ( "RemAIDeck".equals(variable) ) {
this.removedFromAIDecks = "True".equalsIgnoreCase(value);
} else if ( "RemRandomDeck".equals(variable) ) {
this.removedFromRandomDecks = "True".equalsIgnoreCase(value);
} else if ( "Picture".equals(variable) ) {
this.pictureUrl[this.curFace] = value;
}
} else if (line.startsWith("SetInfo:")) { } else if (line.startsWith("SetInfo:")) {
CardRulesReader.parseSetInfoLine(line, this.characteristics[this.curCharacteristics].getSetsData()); CardRulesReader.parseSetInfoLine(value, this.faces[this.curFace].getSetsData());
} }
break; break;
case 'T': case 'T':
if (line.startsWith("Types:")) { if ("Types".equals(key)) {
this.characteristics[this.curCharacteristics].setCardType(CardType.parse(CardRulesReader.getValueAfterKey( this.faces[this.curFace].setType(CardType.parse(value));
line, "Types:")));
} }
break; break;
} }
@@ -194,7 +217,7 @@ public class CardRulesReader {
* @param setsData * @param setsData
* the current mapping of set names to CardInSet instances * the current mapping of set names to CardInSet instances
*/ */
public static void parseSetInfoLine(final String line, final Map<String, CardInSet> setsData) { public static void parseSetInfoLine(final String value, final Map<String, CardInSet> setsData) {
final int setCodeIx = 0; final int setCodeIx = 0;
final int rarityIx = 1; final int rarityIx = 1;
final int numPicIx = 3; final int numPicIx = 3;
@@ -202,7 +225,6 @@ public class CardRulesReader {
// Sample SetInfo line: // Sample SetInfo line:
// SetInfo:POR|Land|http://magiccards.info/scans/en/po/203.jpg|4 // SetInfo:POR|Land|http://magiccards.info/scans/en/po/203.jpg|4
final String value = line.substring("SetInfo:".length());
final String[] pieces = value.split("\\|"); final String[] pieces = value.split("\\|");
if (pieces.length <= rarityIx) { if (pieces.length <= rarityIx) {

View File

@@ -0,0 +1,37 @@
package forge.card;
/**
* TODO: Write javadoc for this type.
*
*/
public enum CardSplitType
{
None(AggregationMethod.USE_PRIMARY_FACE),
Transform(AggregationMethod.USE_ACTIVE_FACE),
Split(AggregationMethod.AGGREGATE),
Flip(AggregationMethod.USE_PRIMARY_FACE);
private CardSplitType(AggregationMethod calcMode) {
method = calcMode;
}
/**
* @return the calculationMode
*/
public AggregationMethod getAggregationMethod() {
return method;
}
private final AggregationMethod method;
public static CardSplitType smartValueOf(String text) {
if ("DoubleFaced".equals(text)) return Transform;
if ("Alternate".equals(text)) return None;
// Will throw exceptions here if bad text passed
CardSplitType res = CardSplitType.valueOf(text);
return res;
}
}

View File

@@ -86,6 +86,17 @@ public final class CardType implements Comparable<CardType> {
return result; return result;
} }
public static CardType combine(final CardType a, final CardType b) {
CardType result = new CardType();
result.superType.addAll(a.superType);
result.superType.addAll(b.superType);
result.coreType.addAll(a.coreType);
result.coreType.addAll(b.coreType);
result.subType.addAll(a.subType);
result.subType.addAll(b.subType);
return result;
}
private static boolean isMultiwordType(final String type) { private static boolean isMultiwordType(final String type) {
final String[] multiWordTypes = { "Serra's Realm", "Bolas's Meditation Realm" }; final String[] multiWordTypes = { "Serra's Realm", "Bolas's Meditation Realm" };
// no need to loop for only 2 exceptions! // no need to loop for only 2 exceptions!

View File

@@ -0,0 +1,30 @@
package forge.card;
import java.util.Map.Entry;
import forge.card.mana.ManaCost;
/**
* TODO: Write javadoc for this type.
*
*/
public interface ICardCharacteristics {
public abstract String getName();
public abstract CardType getType();
public abstract ManaCost getManaCost();
public abstract ColorSet getColor();
public abstract int getIntPower();
public abstract int getIntToughness();
public abstract String getPower();
public abstract String getToughness();
public abstract int getInitialLoyalty();
public abstract String getOracleText();
public abstract Iterable<String> getKeywords();
public abstract Iterable<Entry<String, CardInSet>> getSetsPrinted();
public abstract CardInSet getEditionInfo(final String setCode);
}

View File

@@ -1,363 +0,0 @@
/*
* Forge: Play Magic: the Gathering.
* Copyright (C) 2011 Forge Team
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package forge.card;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.apache.commons.lang3.StringUtils;
import forge.card.mana.ManaCostShard;
import forge.card.mana.IParserManaCost;
import forge.card.mana.ManaCost;
import forge.properties.ForgeProps;
import forge.properties.NewConstants;
import forge.util.FileUtil;
/** This class can read CardRules from Arch's mtg-data.txt file. */
public final class MtgDataParser implements Iterator<CardRules> {
private final Iterator<String> it;
private final List<String> mtgDataLines;
/**
* Instantiates a new mtg data parser.
*/
public MtgDataParser() {
this.mtgDataLines = FileUtil.readFile(ForgeProps.getFile(NewConstants.MTG_DATA));
this.it = this.mtgDataLines.iterator();
this.skipSetList();
}
private static List<String> setsToSkipPrefixes = new ArrayList<String>();
private static List<String> unSets = new ArrayList<String>(); // take only
// lands from
// there
static {
MtgDataParser.setsToSkipPrefixes.add("VG"); // Vanguard
MtgDataParser.setsToSkipPrefixes.add("ME"); // Mtgo master's editions
MtgDataParser.setsToSkipPrefixes.add("FV"); // From the vaults
// Duel decks... or... should I keep them?
MtgDataParser.setsToSkipPrefixes.add("DVD");
MtgDataParser.setsToSkipPrefixes.add("EVT");
MtgDataParser.setsToSkipPrefixes.add("EVG");
MtgDataParser.setsToSkipPrefixes.add("GVL");
MtgDataParser.setsToSkipPrefixes.add("JVC");
MtgDataParser.setsToSkipPrefixes.add("DDG");
MtgDataParser.setsToSkipPrefixes.add("PVC");
// Archenemy - we cannot play it now anyway
MtgDataParser.setsToSkipPrefixes.add("ARC");
// Planechase - this too
MtgDataParser.setsToSkipPrefixes.add("HOP");
// Reprints
MtgDataParser.setsToSkipPrefixes.add("BRB");
MtgDataParser.setsToSkipPrefixes.add("BTD");
MtgDataParser.setsToSkipPrefixes.add("DKM");
// setsToSkipPrefixes.add("ATH"); // No need to skip it really.
// On gatherer's opinion this cards were released twice in original set
// Promo sets - all cards have been issued in other sets
MtgDataParser.setsToSkipPrefixes.add("SDC");
MtgDataParser.setsToSkipPrefixes.add("ASTRAL");
// Premium decks
MtgDataParser.setsToSkipPrefixes.add("H09");
MtgDataParser.setsToSkipPrefixes.add("H10");
// Un-sets are weird, but lands from there are valuable
MtgDataParser.unSets.add("UNH");
MtgDataParser.unSets.add("UGL");
}
private boolean weHaveNext;
private void skipSetList() {
String nextLine = this.it.next();
while ((nextLine.length() > 0) && this.it.hasNext()) {
nextLine = this.it.next();
}
this.weHaveNext = this.it.hasNext();
}
/*
* (non-Javadoc)
*
* @see java.util.Iterator#hasNext()
*/
@Override
public boolean hasNext() {
return this.weHaveNext;
}
private final CardRuleCharacteristics[] chars = new CardRuleCharacteristics[2];
/*
* (non-Javadoc)
*
* @see java.util.Iterator#next()
*/
@Override
public CardRules next() {
boolean hasOtherPart = false;
this.chars[0] = new CardRuleCharacteristics();
final Map<String, CardInSet> sets = new HashMap<String, CardInSet>();
String nextline = this.readSingleCard(this.chars[0]);
if (nextline != null) {
if (nextline.equals("----")) {
hasOtherPart = true;
this.chars[1] = new CardRuleCharacteristics();
nextline = this.readSingleCard(this.chars[1]);
}
if (!nextline.isEmpty()) {
final String setsLine = nextline;
final boolean isBasicLand = this.chars[0].getCardType().isLand()
&& this.chars[0].getCardType().isBasic();
this.chars[0].setSetsData(this.getValidEditions(setsLine, isBasicLand));
if (this.chars[1] != null) {
this.chars[1].setSetsData(this.getValidEditions(setsLine, isBasicLand));
}
}
}
// feel free to return null after this line
if (sets.isEmpty()) {
return null;
} // that was a bad card - it won't be added by invoker
if (this.chars[0] == null) {
return null;
}
final CardRules otherPart = hasOtherPart ? new CardRules(this.chars[1], null, hasOtherPart, null, false, false)
: null;
return new CardRules(this.chars[0], null, hasOtherPart, otherPart, false, false);
}
private String readSingleCard(final CardRuleCharacteristics ret) {
if (!this.it.hasNext()) {
this.weHaveNext = false;
return null;
}
ret.setCardName(this.it.next());
if (!this.it.hasNext()) {
this.weHaveNext = false;
return null;
}
String manaCost = this.it.next();
ret.setManaCost(ManaCost.NO_COST);
CardType type = null;
if (manaCost.startsWith("{")) {
ret.setManaCost(new ManaCost(new ManaParserMtgData(manaCost)));
if (!this.it.hasNext()) {
this.weHaveNext = false;
return null;
}
type = CardType.parse(this.it.next());
} else { // Land?
type = CardType.parse(manaCost);
manaCost = null;
}
ret.setPtLine(null);
if (type.isCreature() || type.isPlaneswalker()) {
if (!this.it.hasNext()) {
this.weHaveNext = false;
return null;
}
ret.setPtLine(this.it.next());
}
final String nextline = this.it.next();
final ArrayList<String> rules = new ArrayList<String>();
while ((nextline != null)
&& !nextline.isEmpty()
&& !nextline.equals("----")
&& !java.util.regex.Pattern.matches(
"([A-Z0-9][A-Z0-9][A-Z0-9] [CURM], )*[A-Z0-9][A-Z0-9][A-Z0-9] [CURM]", nextline)) {
rules.add(nextline);
}
ret.setCardRules(StringUtils.join(rules, '\n'));
return nextline;
}
private Map<String, CardInSet> getValidEditions(final String sets, final boolean isBasicLand) {
final String[] setsData = sets.split(", ");
final Map<String, CardInSet> result = new HashMap<String, CardInSet>();
for (final String element : setsData) {
final int spacePos = element.indexOf(' ');
final String setCode = element.substring(0, spacePos);
boolean shouldSkip = false;
for (final String s : MtgDataParser.setsToSkipPrefixes) {
if (setCode.startsWith(s)) {
shouldSkip = true;
break;
}
}
for (final String s : MtgDataParser.unSets) {
if (setCode.startsWith(s) && !isBasicLand) {
shouldSkip = true;
break;
}
}
if (shouldSkip) {
continue;
}
result.put(setCode, MtgDataParser.parseCardInSet(element, spacePos));
}
return result;
}
/**
* Parses the card in set.
*
* @param unparsed
* the unparsed
* @param spaceAt
* the space at
* @return the card in set
*/
public static CardInSet parseCardInSet(final String unparsed, final int spaceAt) {
final 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;
final int bracketAt = unparsed.indexOf('(', spaceAt);
if (-1 != bracketAt) {
final String sN = unparsed.substring(bracketAt + 2, unparsed.indexOf(')', bracketAt));
number = Integer.parseInt(sN);
}
return new CardInSet(rating, number, null);
}
/*
* (non-Javadoc)
*
* @see java.util.Iterator#remove()
*/
@Override
public void remove() {
}
/**
* This is a mana-parser for mana written in curly braces like {2}{R}{B}.
*/
public static final class ManaParserMtgData implements IParserManaCost {
private final String cost;
private int nextBracket;
private int colorlessCost;
/**
* Instantiates a new mana parser mtg data.
*
* @param cost0
* the cost0
*/
public ManaParserMtgData(final String cost0) {
this.cost = cost0;
// System.out.println(cost);
this.nextBracket = cost0.indexOf('{');
this.colorlessCost = 0;
}
/*
* (non-Javadoc)
*
* @see forge.card.CardManaCost.ManaParser#getTotalColorlessCost()
*/
@Override
public int getTotalColorlessCost() {
if (this.hasNext()) {
throw new RuntimeException("Colorless cost should be obtained after iteration is complete");
}
return this.colorlessCost;
}
/*
* (non-Javadoc)
*
* @see java.util.Iterator#hasNext()
*/
@Override
public boolean hasNext() {
return this.nextBracket != -1;
}
/*
* (non-Javadoc)
*
* @see java.util.Iterator#next()
*/
@Override
public ManaCostShard next() {
final int closeBracket = this.cost.indexOf('}', this.nextBracket);
final String unparsed = this.cost.substring(this.nextBracket + 1, closeBracket);
this.nextBracket = this.cost.indexOf('{', closeBracket + 1);
// System.out.println(unparsed);
if (StringUtils.isNumeric(unparsed)) {
this.colorlessCost += Integer.parseInt(unparsed);
return null;
}
return ManaCostShard.parseNonGeneric(unparsed);
}
/*
* (non-Javadoc)
*
* @see java.util.Iterator#remove()
*/
@Override
public void remove() {
} // unsuported
}
}

View File

@@ -227,7 +227,7 @@ public class CardFactory {
public final Card getCard(final CardPrinted cp, final Player owner) { public final Card getCard(final CardPrinted cp, final Player owner) {
//System.out.println(cardName); //System.out.println(cardName);
Card c = this.getCard2(cp.getRules().getCardScript(), owner); Card c = this.getCard2(cp.getRules().getForgeScript(), owner);
if (c != null) { if (c != null) {
c.setCurSetCode(cp.getEdition()); c.setCurSetCode(cp.getEdition());

View File

@@ -33,10 +33,10 @@ import forge.card.ColorSet;
*/ */
public final class ManaCost implements Comparable<ManaCost> { public final class ManaCost implements Comparable<ManaCost> {
private final List<ManaCostShard> shards; private List<ManaCostShard> shards;
private final int genericCost; private final int genericCost;
private final boolean hasNoCost; // lands cost private final boolean hasNoCost; // lands cost
private final String stringValue; // precalculated for toString; private String stringValue; // precalculated for toString;
private Float compareWeight = null; private Float compareWeight = null;
@@ -49,7 +49,11 @@ public final class ManaCost implements Comparable<ManaCost> {
private ManaCost(int cmc) { private ManaCost(int cmc) {
this.hasNoCost = cmc < 0; this.hasNoCost = cmc < 0;
this.genericCost = cmc < 0 ? 0 : cmc; this.genericCost = cmc < 0 ? 0 : cmc;
this.shards = Collections.unmodifiableList(new ArrayList<ManaCostShard>()); sealClass(new ArrayList<ManaCostShard>());
}
private void sealClass(List<ManaCostShard> shards0) {
this.shards = Collections.unmodifiableList(shards0);
this.stringValue = this.getSimpleString(); this.stringValue = this.getSimpleString();
} }
@@ -75,8 +79,7 @@ public final class ManaCost implements Comparable<ManaCost> {
this.genericCost = parser.getTotalColorlessCost(); // collect generic this.genericCost = parser.getTotalColorlessCost(); // collect generic
// mana // mana
// here // here
this.shards = Collections.unmodifiableList(shardsTemp); sealClass(shardsTemp);
this.stringValue = this.getSimpleString();
} }
private String getSimpleString() { private String getSimpleString() {
@@ -256,4 +259,19 @@ public final class ManaCost implements Comparable<ManaCost> {
return true; return true;
} }
/**
* TODO: Write javadoc for this method.
* @param manaCost
* @param manaCost2
* @return
*/
public static ManaCost combine(ManaCost a, ManaCost b) {
ManaCost res = new ManaCost(a.genericCost + b.genericCost);
List<ManaCostShard> sh = new ArrayList<ManaCostShard>();
sh.addAll(a.shards);
sh.addAll(b.shards);
res.sealClass(sh);
return res;
}
} }

View File

@@ -306,7 +306,7 @@ public class Deck extends DeckBase implements Iterable<Entry<DeckSection, CardPo
public boolean apply(Deck d) { public boolean apply(Deck d) {
for(Entry<DeckSection, CardPool> cp: d) { for(Entry<DeckSection, CardPool> cp: d) {
for(Entry<CardPrinted, Integer> e : cp.getValue()) { for(Entry<CardPrinted, Integer> e : cp.getValue()) {
if ( e.getKey().getRules().getRemAIDecks() ) if ( e.getKey().getRules().getAiHints().getRemAIDecks() )
return false; return false;
} }
} }

View File

@@ -43,14 +43,14 @@ public class GenerateDeckUtil {
public static final Predicate<CardRules> AI_CAN_PLAY = new Predicate<CardRules>() { public static final Predicate<CardRules> AI_CAN_PLAY = new Predicate<CardRules>() {
@Override @Override
public boolean apply(CardRules c) { public boolean apply(CardRules c) {
return !c.getRemAIDecks() && !c.getRemRandomDecks(); return !c.getAiHints().getRemAIDecks() && !c.getAiHints().getRemRandomDecks();
} }
}; };
public static final Predicate<CardRules> HUMAN_CAN_PLAY = new Predicate<CardRules>() { public static final Predicate<CardRules> HUMAN_CAN_PLAY = new Predicate<CardRules>() {
@Override @Override
public boolean apply(CardRules c) { public boolean apply(CardRules c) {
return !c.getRemRandomDecks(); return !c.getAiHints().getRemRandomDecks();
} }
}; };

View File

@@ -195,7 +195,7 @@ public class GameNew {
for ( Entry<DeckSection, CardPool> ds : toUse ) { for ( Entry<DeckSection, CardPool> ds : toUse ) {
for (Entry<CardPrinted, Integer> cp : ds.getValue()) { for (Entry<CardPrinted, Integer> cp : ds.getValue()) {
if ( cp.getKey().getRules().getRemAIDecks() ) if ( cp.getKey().getRules().getAiHints().getRemAIDecks() )
result.add(cp.getKey()); result.add(cp.getKey());
} }
} }
@@ -207,7 +207,7 @@ public class GameNew {
Set<CardPrinted> myRemovedAnteCards = new HashSet<CardPrinted>(); Set<CardPrinted> myRemovedAnteCards = new HashSet<CardPrinted>();
for ( Entry<DeckSection, CardPool> ds : toUse ) { for ( Entry<DeckSection, CardPool> ds : toUse ) {
for (Entry<CardPrinted, Integer> cp : ds.getValue()) { for (Entry<CardPrinted, Integer> cp : ds.getValue()) {
if ( cp.getKey().getRules().rulesContain(keywordToRemove) ) if ( Iterables.contains(cp.getKey().getRules().getKeywords(), keywordToRemove) )
myRemovedAnteCards.add(cp.getKey()); myRemovedAnteCards.add(cp.getKey());
} }
} }

View File

@@ -79,7 +79,7 @@ public class BoosterDraftAI {
for(Pair<CardPrinted, Double> p : rankedCards) { for(Pair<CardPrinted, Double> p : rankedCards) {
// If a card is not ai playable, somewhat decrease its rating // If a card is not ai playable, somewhat decrease its rating
if( p.getKey().getRules().getRemAIDecks() ) if( p.getKey().getRules().getAiHints().getRemAIDecks() )
p.setValue(p.getValue() + TAKE_BEST_THRESHOLD); p.setValue(p.getValue() + TAKE_BEST_THRESHOLD);
// if I cannot choose more colors, and the card cannot be played with chosen colors, decrease its rating. // if I cannot choose more colors, and the card cannot be played with chosen colors, decrease its rating.

View File

@@ -18,6 +18,7 @@ import com.google.common.collect.Iterables;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
import forge.Constant.Preferences; import forge.Constant.Preferences;
import forge.card.CardAiHints;
import forge.card.MagicColor; import forge.card.MagicColor;
import forge.card.ColorSet; import forge.card.ColorSet;
import forge.card.CardRules; import forge.card.CardRules;
@@ -516,11 +517,9 @@ public class LimitedDeck {
*/ */
private int addDeckHintsCards(CardPrinted cardToAdd, int num) { private int addDeckHintsCards(CardPrinted cardToAdd, int num) {
// cards with DeckHints will try to grab additional cards from the pool // cards with DeckHints will try to grab additional cards from the pool
if (cardToAdd.getRules().getDeckHints() != null DeckHints hints = cardToAdd.getRules().getAiHints().getDeckHints();
&& cardToAdd.getRules().getDeckHints().getType() != DeckHints.Type.NONE) { if (hints != null && hints.getType() != DeckHints.Type.NONE) {
DeckHints hints = cardToAdd.getRules().getDeckHints(); Iterable<CardPrinted> onColor = Iterables.filter(aiPlayables, Predicates.compose(hasColor, CardPrinted.FN_GET_RULES));
Iterable<CardPrinted> onColor = Iterables.filter(aiPlayables,
Predicates.compose(hasColor, CardPrinted.FN_GET_RULES));
List<CardPrinted> comboCards = hints.filter(onColor); List<CardPrinted> comboCards = hints.filter(onColor);
if (Preferences.DEV_MODE) { if (Preferences.DEV_MODE) {
System.out.println("Found " + comboCards.size() + " cards for " + cardToAdd.getName()); System.out.println("Found " + comboCards.size() + " cards for " + cardToAdd.getName());
@@ -557,16 +556,17 @@ public class LimitedDeck {
int numOthers = 0; int numOthers = 0;
for (ListIterator<CardPrinted> it = deckList.listIterator(); it.hasNext();) { for (ListIterator<CardPrinted> it = deckList.listIterator(); it.hasNext();) {
CardPrinted card = it.next(); CardPrinted card = it.next();
if (card.getRules().getRemRandomDecks()) { CardAiHints ai = card.getRules().getAiHints();
if (ai.getRemRandomDecks()) {
List<CardPrinted> comboCards = new ArrayList<CardPrinted>(); List<CardPrinted> comboCards = new ArrayList<CardPrinted>();
if (card.getRules().getDeckNeeds() != null if (ai.getDeckNeeds() != null
&& card.getRules().getDeckNeeds().getType() != DeckHints.Type.NONE) { && ai.getDeckNeeds().getType() != DeckHints.Type.NONE) {
DeckHints needs = card.getRules().getDeckNeeds(); DeckHints needs = ai.getDeckNeeds();
comboCards.addAll(needs.filter(deckList)); comboCards.addAll(needs.filter(deckList));
} }
if (card.getRules().getDeckHints() != null if (ai.getDeckHints() != null
&& card.getRules().getDeckHints().getType() != DeckHints.Type.NONE) { && ai.getDeckHints().getType() != DeckHints.Type.NONE) {
DeckHints hints = card.getRules().getDeckHints(); DeckHints hints = ai.getDeckHints();
comboCards.addAll(hints.filter(deckList)); comboCards.addAll(hints.filter(deckList));
} }
if (comboCards.isEmpty()) { if (comboCards.isEmpty()) {

View File

@@ -30,6 +30,7 @@ import javax.swing.table.TableColumnModel;
import com.google.common.base.Function; import com.google.common.base.Function;
import forge.Singletons; import forge.Singletons;
import forge.card.CardAiHints;
import forge.card.ColorSet; import forge.card.ColorSet;
import forge.card.CardEdition; import forge.card.CardEdition;
import forge.card.CardRarity; import forge.card.CardRarity;
@@ -328,7 +329,7 @@ public final class SColumnUtil {
if (i instanceof CardPrinted) { if (i instanceof CardPrinted) {
result = ((CardPrinted) i).getRules().getIntPower(); result = ((CardPrinted) i).getRules().getIntPower();
if (result == null) { if (result == null) {
result = Integer.valueOf(((CardPrinted) i).getRules().getLoyalty()); result = Integer.valueOf(((CardPrinted) i).getRules().getInitialLoyalty());
if (result == null) { result = -1; } if (result == null) { result = -1; }
} }
} }
@@ -357,11 +358,18 @@ public final class SColumnUtil {
} }
private static Integer toAiCmp(final InventoryItem i) { private static Integer toAiCmp(final InventoryItem i) {
return i instanceof CardPrinted ? ((CardPrinted) i).getRules().getAiStatusComparable() : Integer.valueOf(-1); return i instanceof CardPrinted ? ((CardPrinted) i).getRules().getAiHints().getAiStatusComparable() : Integer.valueOf(-1);
} }
private static String toAiStr(final InventoryItem i) { private static String toAiStr(final InventoryItem i) {
return i instanceof CardPrinted ? ((CardPrinted) i).getRules().getAiStatus() : "n/a"; if (!(i instanceof CardPrinted))
return "n/a";
CardPrinted cp = (CardPrinted) i;
CardAiHints ai = cp.getRules().getAiHints();
return ai.getRemAIDecks() ? (ai.getRemRandomDecks() ? "AI ?" : "AI")
: (ai.getRemRandomDecks() ? "?" : "");
} }
private static Double toRankingCmp(final InventoryItem i) { private static Double toRankingCmp(final InventoryItem i) {

View File

@@ -21,6 +21,8 @@ import java.io.File;
import java.util.ArrayList; import java.util.ArrayList;
import forge.card.CardRules; import forge.card.CardRules;
import forge.card.CardSplitType;
import forge.card.ICardCharacteristics;
import forge.gui.GuiDisplayUtil; import forge.gui.GuiDisplayUtil;
import forge.item.CardDb; import forge.item.CardDb;
import forge.item.CardPrinted; import forge.item.CardPrinted;
@@ -64,12 +66,12 @@ public class GuiDownloadPicturesLQ extends GuiDownloader {
for (final CardPrinted c : CardDb.instance().getUniqueCards()) { for (final CardPrinted c : CardDb.instance().getUniqueCards()) {
//System.out.println(c.getName()); //System.out.println(c.getName());
CardRules firstSide = c.getRules(); CardRules cardRules = c.getRules();
this.createDLObjects(firstSide); this.createDLObjects(cardRules.getPictureUrl(), cardRules.getMainPart().getName());
CardRules secondSide = firstSide.getSlavePart(); ICardCharacteristics secondSide = cardRules.getOtherPart();
if (secondSide != null) { if (secondSide != null && cardRules.getSplitType() == CardSplitType.Transform) {
this.createDLObjects(secondSide); this.createDLObjects(cardRules.getPictureOtherSideUrl(), secondSide.getName());
} }
} }
@@ -85,13 +87,12 @@ public class GuiDownloadPicturesLQ extends GuiDownloader {
return downloads.toArray(new DownloadObject[downloads.size()]); return downloads.toArray(new DownloadObject[downloads.size()]);
} // getNeededImages() } // getNeededImages()
private void createDLObjects(final CardRules c) { private void createDLObjects(final String url, final String cardName) {
final String url = c.getPictureUrl();
if (url != null && !url.isEmpty()) { if (url != null && !url.isEmpty()) {
final String[] urls = url.split("\\\\"); final String[] urls = url.split("\\\\");
final String sName = GuiDisplayUtil.cleanString(c.getName()); final String sName = GuiDisplayUtil.cleanString(cardName);
addDownloadObject(urls[0], new File(baseFolder, sName + ".jpg")); addDownloadObject(urls[0], new File(baseFolder, sName + ".jpg"));
for (int j = 1; j < urls.length; j++) { for (int j = 1; j < urls.length; j++) {

View File

@@ -27,6 +27,7 @@ import com.google.common.collect.Iterables;
import forge.CardUtil; import forge.CardUtil;
import forge.Singletons; import forge.Singletons;
import forge.card.CardEdition; import forge.card.CardEdition;
import forge.card.CardSplitType;
import forge.item.CardDb; import forge.item.CardDb;
import forge.item.CardPrinted; import forge.item.CardPrinted;
import forge.properties.ForgeProps; import forge.properties.ForgeProps;
@@ -101,8 +102,8 @@ public class GuiDownloadSetPicturesLQ extends GuiDownloader {
} }
this.addCardToList(cList, c, c.getRules().getName()); this.addCardToList(cList, c, c.getRules().getName());
if (c.getRules().isDoubleFaced()) { if (c.getRules().getSplitType() == CardSplitType.Transform) {
this.addCardToList(cList, c, c.getRules().getSlavePart().getName()); this.addCardToList(cList, c, c.getRules().getOtherPart().getName());
} }
} }

View File

@@ -95,13 +95,13 @@ public enum VSubmenuVanguard implements IVSubmenu<CSubmenuVanguard> {
aiListData.add("Random"); aiListData.add("Random");
for (CardPrinted cp : getAllAvatars()) { for (CardPrinted cp : getAllAvatars()) {
humanListData.add(cp); humanListData.add(cp);
if (!cp.getRules().getRemRandomDecks()) { if (!cp.getRules().getAiHints().getRemRandomDecks()) {
nonRandomHumanAvatars.add(cp); nonRandomHumanAvatars.add(cp);
} }
if (!cp.getRules().getRemAIDecks()) { if (!cp.getRules().getAiHints().getRemAIDecks()) {
aiListData.add(cp); aiListData.add(cp);
allAiAvatars.add(cp); allAiAvatars.add(cp);
if (!cp.getRules().getRemRandomDecks()) { if (!cp.getRules().getAiHints().getRemRandomDecks()) {
nonRandomAiAvatars.add(cp); nonRandomAiAvatars.add(cp);
} }
} }

View File

@@ -29,7 +29,7 @@ public class DeckHintsTest {
void test() { void test() {
CardPrinted cp = readCard("griffin_rider.txt"); CardPrinted cp = readCard("griffin_rider.txt");
Assert.assertEquals("Griffin Rider", cp.getName()); Assert.assertEquals("Griffin Rider", cp.getName());
DeckHints hints = cp.getRules().getDeckHints(); DeckHints hints = cp.getRules().getAiHints().getDeckHints();
Assert.assertNotNull(hints); Assert.assertNotNull(hints);
Assert.assertEquals(DeckHints.Type.TYPE, hints.getType()); Assert.assertEquals(DeckHints.Type.TYPE, hints.getType());
@@ -50,7 +50,7 @@ public class DeckHintsTest {
void testCards() { void testCards() {
CardPrinted cp = readCard("throne_of_empires.txt"); CardPrinted cp = readCard("throne_of_empires.txt");
Assert.assertEquals("Throne of Empires", cp.getName()); Assert.assertEquals("Throne of Empires", cp.getName());
DeckHints hints = cp.getRules().getDeckHints(); DeckHints hints = cp.getRules().getAiHints().getDeckHints();
Assert.assertNotNull(hints); Assert.assertNotNull(hints);
Assert.assertEquals(DeckHints.Type.NAME, hints.getType()); Assert.assertEquals(DeckHints.Type.NAME, hints.getType());
@@ -71,7 +71,7 @@ public class DeckHintsTest {
@Test(timeOut = 1000, enabled = true) @Test(timeOut = 1000, enabled = true)
void testKeywords() { void testKeywords() {
CardPrinted cp = readCard("mwonvuli_beast_tracker.txt"); CardPrinted cp = readCard("mwonvuli_beast_tracker.txt");
DeckHints hints = cp.getRules().getDeckHints(); DeckHints hints = cp.getRules().getAiHints().getDeckHints();
Assert.assertNotNull(hints); Assert.assertNotNull(hints);
Assert.assertEquals(DeckHints.Type.KEYWORD, hints.getType()); Assert.assertEquals(DeckHints.Type.KEYWORD, hints.getType());
@@ -90,7 +90,7 @@ public class DeckHintsTest {
@Test(timeOut = 1000, enabled = true) @Test(timeOut = 1000, enabled = true)
void testColor() { void testColor() {
CardPrinted cp = readCard("wurms_tooth.txt"); CardPrinted cp = readCard("wurms_tooth.txt");
DeckHints hints = cp.getRules().getDeckNeeds(); DeckHints hints = cp.getRules().getAiHints().getDeckNeeds();
Assert.assertNotNull(hints); Assert.assertNotNull(hints);
Assert.assertEquals(DeckHints.Type.COLOR, hints.getType()); Assert.assertEquals(DeckHints.Type.COLOR, hints.getType());
@@ -110,7 +110,7 @@ public class DeckHintsTest {
@Test(timeOut = 1000, enabled = false) @Test(timeOut = 1000, enabled = false)
void testNoFilter() { void testNoFilter() {
CardPrinted cp = readCard("assault_griffin.txt"); CardPrinted cp = readCard("assault_griffin.txt");
DeckHints hints = cp.getRules().getDeckHints(); DeckHints hints = cp.getRules().getAiHints().getDeckHints();
Assert.assertEquals("Assault Griffin", cp.getName()); Assert.assertEquals("Assault Griffin", cp.getName());
Assert.assertNotNull(hints); Assert.assertNotNull(hints);
Assert.assertEquals(DeckHints.Type.NONE, hints.getType()); Assert.assertEquals(DeckHints.Type.NONE, hints.getType());