moved all items to core, decks were included too.

This commit is contained in:
Maxmtg
2013-11-20 08:34:37 +00:00
parent 0786012ed8
commit 4d3945f5a4
34 changed files with 457 additions and 498 deletions

View File

@@ -1,71 +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;
import java.util.ArrayList;
import java.util.List;
/**
* <p>
* Constant interface.
* </p>
*
* @author Forge
* @version $Id$
*/
public final class Constant {
// used to pass information between the GUI screens
/**
* The Class Runtime.
*/
public static class Preferences {
/** The Constant DevMode. */
// one for normal mode, one for quest mode
public static boolean DEV_MODE;
/** The Constant UpldDrft. */
public static boolean UPLOAD_DRAFT;
}
public static class Runtime {
/** The Constant NetConn. */
public static volatile boolean NET_CONN = false;
/** The Constant width. */
public static final int WIDTH = 300;
/** The Constant height. */
public static final int HEIGHT = 0;
}
/**
* The Interface Keywords.
*/
public static class Keywords {
/** The loaded. */
public static final boolean[] LOADED = { false };
/** The Non stacking list. */
public static final List<String> NON_STACKING_LIST = new ArrayList<String>();
}
} // Constant

View File

@@ -0,0 +1,276 @@
/*
* 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.deck;
import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
import java.util.EnumMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.TreeSet;
import org.apache.commons.lang3.StringUtils;
import com.google.common.base.Function;
import forge.card.CardDb;
import forge.deck.io.DeckFileHeader;
import forge.deck.io.DeckSerializer;
import forge.item.PaperCard;
import forge.item.IPaperCard;
import forge.util.FileSection;
import forge.util.FileUtil;
import forge.util.ItemPoolSorter;
import forge.util.ItemPoolView;
/**
* <p>
* Deck class.
* </p>
*
* The set of MTG legal cards that become player's library when the game starts.
* Any other data is not part of a deck and should be stored elsewhere. Current
* fields allowed for deck metadata are Name, Title, Description and Deck Type.
*/
@SuppressWarnings("serial")
public class Deck extends DeckBase implements Iterable<Entry<DeckSection, CardPool>> {
private final Map<DeckSection, CardPool> parts = new EnumMap<DeckSection, CardPool>(DeckSection.class);
private final Set<String> tags = new TreeSet<String>(String.CASE_INSENSITIVE_ORDER);
// gameType is from Constant.GameType, like GameType.Regular
/**
* <p>
* Decks have their named finalled.
* </p>
*/
public Deck() {
this("");
}
/**
* Instantiates a new deck.
*
* @param name0 the name0
*/
public Deck(final String name0) {
super(name0);
getOrCreate(DeckSection.Main);
}
@Override
public int hashCode() {
return this.getName().hashCode();
}
/** {@inheritDoc} */
@Override
public String toString() {
return this.getName();
}
public CardPool getMain() {
return this.parts.get(DeckSection.Main);
}
// may return nulls
public CardPool get(DeckSection deckSection) {
return this.parts.get(deckSection);
}
public boolean has(DeckSection deckSection) {
final CardPool cp = get(deckSection);
return cp != null && !cp.isEmpty();
}
// will return new if it was absent
public CardPool getOrCreate(DeckSection deckSection) {
CardPool p = get(deckSection);
if ( p != null )
return p;
p = new CardPool();
this.parts.put(deckSection, p);
return p;
}
/* (non-Javadoc)
* @see forge.deck.DeckBase#cloneFieldsTo(forge.deck.DeckBase)
*/
@Override
protected void cloneFieldsTo(final DeckBase clone) {
super.cloneFieldsTo(clone);
final Deck result = (Deck) clone;
for(Entry<DeckSection, CardPool> kv : parts.entrySet()) {
CardPool cp = new CardPool();
result.parts.put(kv.getKey(), cp);
cp.addAll(kv.getValue());
}
}
/*
* (non-Javadoc)
*
* @see forge.deck.DeckBase#newInstance(java.lang.String)
*/
@Override
protected DeckBase newInstance(final String name0) {
return new Deck(name0);
}
/**
* From file.
*
* @param deckFile the deck file
* @return the deck
*/
public static Deck fromFile(final File deckFile) {
return Deck.fromSections(FileSection.parseSections(FileUtil.readFile(deckFile)));
}
/**
* From sections.
*
* @param sections the sections
* @return the deck
*/
public static Deck fromSections(final Map<String, List<String>> sections) {
return Deck.fromSections(sections, false);
}
/**
* From sections.
*
* @param sections the sections
* @param canThrowExtendedErrors the can throw extended errors
* @return the deck
*/
public static Deck fromSections(final Map<String, List<String>> sections, final boolean canThrowExtendedErrors) {
if ((sections == null) || sections.isEmpty()) {
return null;
}
final DeckFileHeader dh = DeckSerializer.readDeckMetadata(sections, canThrowExtendedErrors);
if (dh == null) {
return null;
}
final Deck d = new Deck(dh.getName());
d.setComment(dh.getComment());
d.tags.addAll(dh.getTags());
for(Entry<String, List<String>> s : sections.entrySet()) {
DeckSection sec = DeckSection.smartValueOf(s.getKey());
if ( null == sec )
continue;
CardPool pool = CardPool.fromCardList(s.getValue());
// I used to store planes and schemes under sideboard header, so this will assign them to a correct section
IPaperCard sample = pool.get(0);
if ( sample != null && ( sample.getRules().getType().isPlane() || sample.getRules().getType().isPhenomenon() ) )
sec = DeckSection.Planes;
if ( sample != null && sample.getRules().getType().isScheme() )
sec = DeckSection.Schemes;
d.parts.put(sec, pool);
}
return d;
}
private static List<String> writeCardPool(final ItemPoolView<PaperCard> pool) {
final List<Entry<PaperCard, Integer>> main2sort = pool.getOrderedList();
Collections.sort(main2sort, ItemPoolSorter.BY_NAME_THEN_SET);
final List<String> out = new ArrayList<String>();
for (final Entry<PaperCard, Integer> e : main2sort) {
out.add(serializeSingleCard(e.getKey(), e.getValue()));
}
return out;
}
private static String serializeSingleCard(PaperCard card, Integer n) {
final boolean hasBadSetInfo = "???".equals(card.getEdition()) || StringUtils.isBlank(card.getEdition());
StringBuilder sb = new StringBuilder();
sb.append(n).append(" ").append(card.getName());
if (!hasBadSetInfo) {
sb.append("|").append(card.getEdition());
}
if(card.isFoil()) {
sb.append(CardDb.foilSuffix);
}
return sb.toString();
}
/**
* <p>
* writeDeck.
* </p>
*
* @return the list
*/
public List<String> save() {
final List<String> out = new ArrayList<String>();
out.add(String.format("[metadata]"));
out.add(String.format("%s=%s", DeckFileHeader.NAME, this.getName().replaceAll("\n", "")));
// these are optional
if (this.getComment() != null) {
out.add(String.format("%s=%s", DeckFileHeader.COMMENT, this.getComment().replaceAll("\n", "")));
}
if (!this.getTags().isEmpty()) {
out.add(String.format("%s=%s", DeckFileHeader.TAGS, StringUtils.join(getTags(), DeckFileHeader.TAGS_SEPARATOR)));
}
for(Entry<DeckSection, CardPool> s : parts.entrySet()) {
out.add(String.format("[%s]", s.getKey().toString()));
out.addAll(Deck.writeCardPool(s.getValue()));
}
return out;
}
public static final Function<Deck, String> FN_NAME_SELECTOR = new Function<Deck, String>() {
@Override
public String apply(Deck arg1) {
return arg1.getName();
}
};
/* (non-Javadoc)
* @see java.lang.Iterable#iterator()
*/
@Override
public Iterator<Entry<DeckSection, CardPool>> iterator() {
return parts.entrySet().iterator();
}
/**
* @return the associated tags, a writable set
*/
public Set<String> getTags() {
return tags;
}
}

View File

@@ -0,0 +1,137 @@
/*
* 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.deck;
import java.io.Serializable;
import forge.util.IHasName;
/**
* TODO: Write javadoc for this type.
*
*/
public abstract class DeckBase implements Serializable, Comparable<DeckBase>, IHasName {
private static final long serialVersionUID = -7538150536939660052L;
// gameType is from Constant.GameType, like GameType.Regular
private final String name;
private String comment = null;
/**
* Instantiates a new deck base.
*
* @param name0 the name0
*/
public DeckBase(final String name0) {
this.name = name0.replace('/', '_');
}
/* (non-Javadoc)
* @see java.lang.Comparable#compareTo(java.lang.Object)
*/
@Override
public int compareTo(final DeckBase d) {
return this.getName().compareTo(d.getName());
}
/** {@inheritDoc} */
@Override
public boolean equals(final Object o) {
if (o instanceof DeckBase) {
final DeckBase d = (DeckBase) o;
return this.getName().equals(d.getName());
}
return false;
}
/*
* (non-Javadoc)
*
* @see java.lang.Object#hashCode()
*/
@Override
public int hashCode() {
return (this.name.hashCode() * 17) + this.name.hashCode();
}
/* (non-Javadoc)
* @see forge.util.IHasName#getName()
*/
public String getName() {
return this.name;
}
/**
* Sets the comment.
*
* @param comment the new comment
*/
public void setComment(final String comment) {
this.comment = comment;
}
/**
* <p>
* getComment.
* </p>
*
* @return a {@link java.lang.String} object.
*/
public String getComment() {
return this.comment;
}
/**
* New instance.
*
* @param name0 the name0
* @return the deck base
*/
protected abstract DeckBase newInstance(String name0);
/**
* Clone fields to.
*
* @param clone the clone
*/
protected void cloneFieldsTo(final DeckBase clone) {
clone.comment = this.comment;
}
/**
* Copy to.
*
* @param name0 the name0
* @return the deck base
*/
public DeckBase copyTo(final String name0) {
final DeckBase obj = this.newInstance(name0);
this.cloneFieldsTo(obj);
return obj;
}
/**
* Gets the best file name.
*
* @return the best file name
*/
public final String getBestFileName() {
return this.getName().replaceAll("[^-_$#@.,{[()]} a-zA-Z0-9]", "");
}
}

View File

@@ -0,0 +1,245 @@
/*
* 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.deck;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map.Entry;
import org.apache.commons.lang3.Range;
import forge.StaticData;
import forge.card.CardCoreType;
import forge.card.ColorSet;
import forge.item.PaperCard;
import forge.item.IPaperCard;
import forge.util.Aggregates;
/**
* GameType is an enum to determine the type of current game. :)
*/
public enum DeckFormat {
// Main board: allowed size SB: restriction Max distinct non basic cards
Constructed ( Range.between(60, Integer.MAX_VALUE), Range.between(0, 15), 4),
QuestDeck ( Range.between(40, Integer.MAX_VALUE), Range.between(0, 15), 4),
Limited ( Range.between(40, Integer.MAX_VALUE), null, Integer.MAX_VALUE),
Commander ( Range.is(99), Range.between(0, 10), 1),
Vanguard ( Range.between(60, Integer.MAX_VALUE), Range.is(0), 4),
Planechase ( Range.between(60, Integer.MAX_VALUE), Range.is(0), 4),
Archenemy ( Range.between(60, Integer.MAX_VALUE), Range.is(0), 4);
private final Range<Integer> mainRange;
private final Range<Integer> sideRange; // null => no check
private final int maxCardCopies;
DeckFormat(Range<Integer> main, Range<Integer> side, int maxCopies) {
mainRange = main;
sideRange = side;
maxCardCopies = maxCopies;
}
/**
* Smart value of.
*
* @param value the value
* @param defaultValue the default value
* @return the game type
*/
public static DeckFormat smartValueOf(final String value, DeckFormat defaultValue) {
if (null == value) {
return defaultValue;
}
final String valToCompate = value.trim();
for (final DeckFormat v : DeckFormat.values()) {
if (v.name().compareToIgnoreCase(valToCompate) == 0) {
return v;
}
}
throw new IllegalArgumentException("No element named " + value + " in enum GameType");
}
/**
* @return the sideRange
*/
public Range<Integer> getSideRange() {
return sideRange;
}
/**
* @return the mainRange
*/
public Range<Integer> getMainRange() {
return mainRange;
}
/**
* @return the maxCardCopies
*/
public int getMaxCardCopies() {
return maxCardCopies;
}
@SuppressWarnings("incomplete-switch")
public String getDeckConformanceProblem(Deck deck) {
if(deck == null) {
return "is not selected";
}
int deckSize = deck.getMain().countAll();
int min = getMainRange().getMinimum();
int max = getMainRange().getMaximum();
if (deckSize < min) {
return String.format("should have a minimum of %d cards", min);
}
if (deckSize > max) {
return String.format("should not exceed a maximum of %d cards", max);
}
switch(this) {
case Commander: //Must contain exactly 1 legendary Commander and a sideboard of 10 or zero cards.
final CardPool cmd = deck.get(DeckSection.Commander);
if (null == cmd || cmd.isEmpty()) {
return "is missing a commander";
}
if (!cmd.get(0).getRules().getType().isLegendary()
|| !cmd.get(0).getRules().getType().isCreature()) {
return "has a commander that is not a legendary creature";
}
ColorSet cmdCI = cmd.get(0).getRules().getColorIdentity();
List<PaperCard> erroneousCI = new ArrayList<PaperCard>();
for(Entry<PaperCard, Integer> cp : deck.get(DeckSection.Main)) {
if(!cp.getKey().getRules().getColorIdentity().hasNoColorsExcept(cmdCI.getColor()))
{
erroneousCI.add(cp.getKey());
}
}
if(deck.has(DeckSection.Sideboard))
{
for(Entry<PaperCard, Integer> cp : deck.get(DeckSection.Sideboard)) {
if(!cp.getKey().getRules().getColorIdentity().hasNoColorsExcept(cmdCI.getColor()))
{
erroneousCI.add(cp.getKey());
}
}
}
if(erroneousCI.size() > 0)
{
StringBuilder sb = new StringBuilder("contains card that do not match the commanders color identity:");
for(PaperCard cp : erroneousCI)
{
sb.append("\n").append(cp.getName());
}
return sb.toString();
}
break;
case Planechase: //Must contain at least 10 planes/phenomenons, but max 2 phenomenons. Singleton.
final CardPool planes = deck.get(DeckSection.Planes);
if (planes == null || planes.countAll() < 10) {
return "should have at least 10 planes";
}
int phenoms = 0;
for (Entry<PaperCard, Integer> cp : planes) {
if (cp.getKey().getRules().getType().typeContains(CardCoreType.Phenomenon)) {
phenoms++;
}
if (cp.getValue() > 1) {
return "must not contain multiple copies of any Plane or Phenomena";
}
}
if (phenoms > 2) {
return "must not contain more than 2 Phenomena";
}
break;
case Archenemy: //Must contain at least 20 schemes, max 2 of each.
final CardPool schemes = deck.get(DeckSection.Schemes);
if (schemes == null || schemes.countAll() < 20) {
return "must contain at least 20 schemes";
}
for (Entry<PaperCard, Integer> cp : schemes) {
if (cp.getValue() > 2) {
return String.format("must not contain more than 2 copies of any Scheme, but has %d of '%s'", cp.getValue(), cp.getKey().getName());
}
}
break;
}
int maxCopies = getMaxCardCopies();
if (maxCopies < Integer.MAX_VALUE) {
//Must contain no more than 4 of the same card
//shared among the main deck and sideboard, except
//basic lands, Shadowborn Apostle and Relentless Rats
CardPool tmp = new CardPool(deck.getMain());
if ( deck.has(DeckSection.Sideboard))
tmp.addAll(deck.get(DeckSection.Sideboard));
if ( deck.has(DeckSection.Commander) && this == Commander)
tmp.addAll(deck.get(DeckSection.Commander));
List<String> limitExceptions = Arrays.asList(new String[]{"Relentless Rats", "Shadowborn Apostle"});
// should group all cards by name, so that different editions of same card are really counted as the same card
for (Entry<String, Integer> cp : Aggregates.groupSumBy(tmp, PaperCard.FN_GET_NAME)) {
IPaperCard simpleCard = StaticData.instance().getCommonCards().getCard(cp.getKey());
boolean canHaveMultiple = simpleCard.getRules().getType().isBasicLand() || limitExceptions.contains(cp.getKey());
if (!canHaveMultiple && cp.getValue() > maxCopies) {
return String.format("must not contain more than %d of '%s' card", maxCopies, cp.getKey());
}
}
}
// The sideboard must contain either 0 or 15 cards
int sideboardSize = deck.has(DeckSection.Sideboard) ? deck.get(DeckSection.Sideboard).countAll() : 0;
Range<Integer> sbRange = getSideRange();
if (sbRange != null && sideboardSize > 0 && !sbRange.contains(sideboardSize)) {
return sbRange.getMinimum() == sbRange.getMaximum()
? String.format("must have a sideboard of %d cards or no sideboard at all", sbRange.getMaximum())
: String.format("must have a sideboard of %d to %d cards or no sideboard at all", sbRange.getMinimum(), sbRange.getMaximum());
}
return null;
}
}

View File

@@ -0,0 +1,32 @@
package forge.deck;
public enum DeckSection {
Avatar(1),
Commander(1),
Main(60),
Sideboard(15),
Planes(10),
Schemes(20);
private final int typicalSize; // Rules enforcement is done in DeckFormat class, this is for reference only
private DeckSection(int commonSize) {
typicalSize = commonSize;
}
public boolean isSingleCard() { return typicalSize == 1; }
public static DeckSection smartValueOf(String value) {
if (value == null) {
return null;
}
final String valToCompate = value.trim();
for (final DeckSection v : DeckSection.values()) {
if (v.name().compareToIgnoreCase(valToCompate) == 0) {
return v;
}
}
return null;
}
}

View File

@@ -0,0 +1,130 @@
/*
* 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.deck.io;
import java.util.Set;
import java.util.TreeSet;
import org.apache.commons.lang3.StringUtils;
import forge.deck.DeckFormat;
import forge.util.FileSection;
/**
* TODO: Write javadoc for this type.
*
*/
public class DeckFileHeader {
/** The Constant NAME. */
public static final String NAME = "Name";
/** The Constant DECK_TYPE. */
public static final String DECK_TYPE = "Deck Type";
public static final String TAGS = "Tags";
public static final String TAGS_SEPARATOR = ",";
/** The Constant COMMENT. */
public static final String COMMENT = "Comment";
private static final String PLAYER = "Player";
private static final String CSTM_POOL = "Custom Pool";
private static final String PLAYER_TYPE = "PlayerType";
private final DeckFormat deckType;
private final boolean customPool;
private final String name;
private final String comment;
private final Set<String> tags;
private final boolean intendedForAi;
/**
* @return the intendedForAi
*/
public boolean isIntendedForAi() {
return intendedForAi;
}
/**
* TODO: Write javadoc for Constructor.
*
* @param kvPairs
* the kv pairs
*/
public DeckFileHeader(final FileSection kvPairs) {
this.name = kvPairs.get(DeckFileHeader.NAME);
this.comment = kvPairs.get(DeckFileHeader.COMMENT);
this.deckType = DeckFormat.smartValueOf(kvPairs.get(DeckFileHeader.DECK_TYPE), DeckFormat.Constructed);
this.customPool = kvPairs.getBoolean(DeckFileHeader.CSTM_POOL);
this.intendedForAi = "computer".equalsIgnoreCase(kvPairs.get(DeckFileHeader.PLAYER)) || "ai".equalsIgnoreCase(kvPairs.get(DeckFileHeader.PLAYER_TYPE));
this.tags = new TreeSet<String>();
String rawTags = kvPairs.get(DeckFileHeader.TAGS);
if( StringUtils.isNotBlank(rawTags) ) {
for( String t: rawTags.split(TAGS_SEPARATOR))
if ( StringUtils.isNotBlank(t))
tags.add(t.trim());
}
}
/**
* Checks if is custom pool.
*
* @return true, if is custom pool
*/
public final boolean isCustomPool() {
return this.customPool;
}
/**
* Gets the name.
*
* @return the name
*/
public final String getName() {
return this.name;
}
/**
* Gets the comment.
*
* @return the comment
*/
public final String getComment() {
return this.comment;
}
/**
* Gets the deck type.
*
* @return the deck type
*/
public final DeckFormat getDeckType() {
return this.deckType;
}
public final Set<String> getTags() {
return tags;
}
}

View File

@@ -0,0 +1,135 @@
/*
* 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.deck.io;
import java.io.File;
import java.io.FilenameFilter;
import java.util.List;
import java.util.Map;
import org.apache.commons.lang3.StringUtils;
import forge.deck.Deck;
import forge.util.FileSection;
import forge.util.FileSectionManual;
import forge.util.FileUtil;
import forge.util.IItemReader;
import forge.util.IItemSerializer;
import forge.util.storage.StorageReaderFolder;
/**
* This class knows how to make a file out of a deck object and vice versa.
*/
public class DeckSerializer extends StorageReaderFolder<Deck> implements IItemSerializer<Deck> {
private final boolean moveWronglyNamedDecks;
public static final String FILE_EXTENSION = ".dck";
public DeckSerializer(final File deckDir0) {
this(deckDir0, false);
}
public DeckSerializer(final File deckDir0, boolean moveWrongDecks) {
super(deckDir0, Deck.FN_NAME_SELECTOR);
moveWronglyNamedDecks = moveWrongDecks;
}
/** Constant <code>DCKFileFilter</code>. */
public static final FilenameFilter DCK_FILE_FILTER = new FilenameFilter() {
@Override
public boolean accept(final File dir, final String name) {
return name.endsWith(FILE_EXTENSION);
}
};
public static void writeDeck(final Deck d, final File f) {
FileUtil.writeFile(f, d.save());
}
@Override
public void save(final Deck unit) {
FileUtil.writeFile(this.makeFileFor(unit), unit.save());
}
@Override
public void erase(final Deck unit) {
this.makeFileFor(unit).delete();
}
public File makeFileFor(final Deck deck) {
return new File(this.directory, deck.getBestFileName() + FILE_EXTENSION);
}
@Override
protected Deck read(final File file) {
final Map<String, List<String>> sections = FileSection.parseSections(FileUtil.readFile(file));
Deck result = Deck.fromSections(sections, true);
if (moveWronglyNamedDecks) {
adjustFileLocation(file, result);
}
return result;
}
private void adjustFileLocation(final File file, final Deck result) {
if (result == null) {
file.delete();
} else {
String destFilename = result.getBestFileName() + FILE_EXTENSION;
if (!file.getName().equals(destFilename)) {
file.renameTo(new File(file.getParentFile().getParentFile(), destFilename));
}
}
}
@Override
protected FilenameFilter getFileFilter() {
return DeckSerializer.DCK_FILE_FILTER;
}
public static DeckFileHeader readDeckMetadata(final Map<String, List<String>> map, final boolean canThrow) {
if (map == null) {
return null;
}
final List<String> metadata = map.get("metadata");
if (metadata != null) {
return new DeckFileHeader(FileSection.parse(metadata, "="));
}
final List<String> general = map.get("general");
if (general != null) {
if (canThrow) {
throw new OldDeckFileFormatException();
}
final FileSectionManual fs = new FileSectionManual();
fs.put(DeckFileHeader.NAME, StringUtils.join(map.get(""), " "));
fs.put(DeckFileHeader.DECK_TYPE, StringUtils.join(general, " "));
return new DeckFileHeader(fs);
}
return null;
}
/* (non-Javadoc)
* @see forge.util.storage.StorageReaderBase#getReaderForFolder(java.io.File)
*/
@Override
public IItemReader<Deck> getReaderForFolder(File subfolder) {
if ( !subfolder.getParentFile().equals(directory) )
throw new UnsupportedOperationException("Only child folders of " + directory + " may be processed");
return new DeckSerializer(subfolder, false);
}
}

View File

@@ -0,0 +1,11 @@
package forge.deck.io;
/**
* TODO: Write javadoc for this type.
*
*/
public class OldDeckFileFormatException extends RuntimeException {
private static final long serialVersionUID = 4107122821742791123L;
}

View File

@@ -0,0 +1,8 @@
/**
*
*/
/**
* @author Max
*
*/
package forge.deck.io;

View File

@@ -0,0 +1,81 @@
/*
* 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.item;
import com.google.common.base.Function;
import forge.StaticData;
import forge.card.CardEdition;
import forge.card.SealedProductTemplate;
import forge.util.MyRandom;
public class BoosterPack extends OpenablePack {
private final int artIndex;
private final int hash;
public static final Function<CardEdition, BoosterPack> FN_FROM_SET = new Function<CardEdition, BoosterPack>() {
@Override
public BoosterPack apply(final CardEdition arg1) {
SealedProductTemplate d = StaticData.instance().getBoosters().get(arg1.getCode());
return new BoosterPack(arg1.getName(), d);
}
};
public BoosterPack(final String name0, final SealedProductTemplate boosterData) {
super(name0, boosterData);
int maxIdx = StaticData.instance().getEditions().get(boosterData.getEdition()).getCntBoosterPictures();
artIndex = MyRandom.getRandom().nextInt(maxIdx) + 1;
hash = super.hashCode() ^ artIndex;
}
public final int getArtIndex() {
return artIndex;
}
@Override
public final String getItemType() {
return "Booster Pack";
}
@Override
public final Object clone() {
return new BoosterPack(name, contents);
}
public SealedProductTemplate getBoosterData() {
return contents;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (!super.equals(obj)) {
return false;
}
BoosterPack other = (BoosterPack)obj;
return artIndex == other.artIndex;
}
@Override
public final int hashCode() {
return hash;
}
}

View File

@@ -0,0 +1,76 @@
/*
* 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.item;
import java.util.ArrayList;
import java.util.List;
import com.google.common.base.Function;
import forge.StaticData;
import forge.card.BoosterGenerator;
import forge.card.CardEdition;
import forge.card.FatPackTemplate;
public class FatPack extends OpenablePack {
public static final Function<CardEdition, FatPack> FN_FROM_SET = new Function<CardEdition, FatPack>() {
@Override
public FatPack apply(final CardEdition arg1) {
FatPackTemplate d = StaticData.instance().getFatPacks().get(arg1.getCode());
return new FatPack(arg1.getName(), d);
}
};
private final FatPackTemplate fpData;
public FatPack(final String name0, final FatPackTemplate fpData0) {
super(name0, StaticData.instance().getBoosters().get(fpData0.getEdition()));
fpData = fpData0;
}
@Override
public String getDescription() {
return fpData.toString() + contents.toString();
}
@Override
public final String getItemType() {
return "Fat Pack";
}
@Override
protected List<PaperCard> generate() {
List<PaperCard> result = new ArrayList<PaperCard>();
for (int i = 0; i < fpData.getCntBoosters(); i++) {
result.addAll(super.generate());
}
result.addAll(BoosterGenerator.getBoosterPack(fpData));
return result;
}
@Override
public final Object clone() {
return new FatPack(name, fpData);
}
@Override
public int getTotalCards() {
return super.getTotalCards() * fpData.getCntBoosters() + fpData.getNumberOfCardsExpected();
}
}

View File

@@ -0,0 +1,65 @@
package forge.item;
import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
/**
* Filtering conditions for miscellaneous InventoryItems.
*/
public abstract class ItemPredicate {
// Static builder methods - they choose concrete implementation by
// themselves
public static final Predicate<Object> IsBoosterPack = Predicates.instanceOf(BoosterPack.class);
public static final Predicate<Object> IsPrebuiltDeck = Predicates.instanceOf(PreconDeck.class);
public static final Predicate<Object> IsFatPack = Predicates.instanceOf(FatPack.class);
/**
* Checks that the inventory item is a Tournament Pack.
*
* @return the predicate
*/
public static final Predicate<InventoryItem> IsTournamentPack = new Predicate<InventoryItem>() {
@Override
public boolean apply(final InventoryItem card) {
return card instanceof TournamentPack && !((TournamentPack) card).isStarterDeck();
}
};
/**
* Checks that the inventory item is a Starter Deck.
*
* @return the predicate
*/
public static final Predicate<InventoryItem> IsStarterDeck = new Predicate<InventoryItem>() {
@Override
public boolean apply(final InventoryItem card) {
return card instanceof TournamentPack && ((TournamentPack) card).isStarterDeck();
}
};
/**
* Checks that the inventory item is a Prebuilt Deck.
*
* @return the predicate
*/
/**
* The Class Presets.
*/
public static class Presets {
/** The Item IsPack. */
@SuppressWarnings("unchecked")
public static final Predicate<InventoryItem> IS_PACK = Predicates.or(IsBoosterPack, IsFatPack, IsTournamentPack);
/** The Item IsDeck. */
public static final Predicate<InventoryItem> IS_DECK = Predicates.or(IsStarterDeck, IsPrebuiltDeck);
}
}

View File

@@ -0,0 +1,107 @@
/*
* 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.item;
import java.util.List;
import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
import com.google.common.collect.Iterables;
import forge.StaticData;
import forge.card.BoosterGenerator;
import forge.card.CardRulesPredicates;
import forge.card.SealedProductTemplate;
import forge.util.Aggregates;
public abstract class OpenablePack implements InventoryItemFromSet {
protected final SealedProductTemplate contents;
protected final String name;
private final int hash;
private List<PaperCard> cards = null;
public OpenablePack(String name0, SealedProductTemplate boosterData) {
if (null == name0) { throw new IllegalArgumentException("name0 must not be null"); }
if (null == boosterData) { throw new IllegalArgumentException("boosterData must not be null"); }
contents = boosterData;
name = name0;
hash = name.hashCode() ^ getClass().hashCode() ^ contents.hashCode();
}
@Override
public final String getName() {
return name + " " + getItemType();
}
public String getDescription() {
return contents.toString();
}
@Override
public final String getEdition() {
return contents.getEdition();
}
public final List<PaperCard> getCards() {
if (null == cards) {
cards = generate();
}
return cards;
}
public int getTotalCards() {
return contents.getNumberOfCardsExpected();
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (this.getClass() != obj.getClass()) {
return false;
}
OpenablePack other = (OpenablePack)obj;
return name.equals(other.name) && contents.equals(other.contents);
}
@Override
public int hashCode() {
return hash;
}
protected List<PaperCard> generate() {
return BoosterGenerator.getBoosterPack(contents);
}
protected PaperCard getRandomBasicLand(final String setCode) {
return this.getRandomBasicLands(setCode, 1).get(0);
}
protected List<PaperCard> getRandomBasicLands(final String setCode, final int count) {
Predicate<PaperCard> cardsRule = Predicates.and(
IPaperCard.Predicates.printedInSet(setCode),
Predicates.compose(CardRulesPredicates.Presets.IS_BASIC_LAND, PaperCard.FN_GET_RULES));
return Aggregates.random(Iterables.filter(StaticData.instance().getCommonCards().getAllCards(), cardsRule), count);
}
}

View File

@@ -0,0 +1,149 @@
/*
* Forge: Play Magic: the Gathering.
* Copyright (C) 2011 Nate
*
* 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.item;
import java.io.File;
import java.io.FilenameFilter;
import java.util.List;
import java.util.Map;
import com.google.common.base.Function;
import forge.StaticData;
import forge.deck.Deck;
import forge.deck.io.DeckSerializer;
import forge.util.FileSection;
import forge.util.FileUtil;
import forge.util.storage.StorageReaderFolder;
/**
* TODO: Write javadoc for this type.
*
*/
public class PreconDeck implements InventoryItemFromSet {
private final Deck deck;
private final String set;
private final String description;
private String imageFilename;
// private final SellRules recommendedDeals;
/*
* (non-Javadoc)
*
* @see forge.item.InventoryItemFromSet#getName()
*/
@Override
public String getName() {
return this.deck.getName();
}
/*
* (non-Javadoc)
*
* @see forge.item.InventoryItem#getType()
*/
@Override
public String getItemType() {
return "Prebuilt Deck";
}
public PreconDeck(final Deck d, String set, String description) {
deck = d;
this.set = set;
this.description = description;
}
public final Deck getDeck() {
return this.deck;
}
/**
* Gets the recommended deals.
*
* @return the recommended deals
*/
// public final SellRules getRecommendedDeals() {
// return this.recommendedDeals;
// }
public final String getImageFilename() {
return imageFilename;
}
/*
* (non-Javadoc)
*
* @see forge.item.InventoryItemFromSet#getSet()
*/
@Override
public String getEdition() {
return this.set;
}
/**
* Gets the description.
*
* @return the description
*/
public final String getDescription() {
return this.description;
}
public static final Function<PreconDeck, String> FN_NAME_SELECTOR = new Function<PreconDeck, String>() {
@Override
public String apply(PreconDeck arg1) {
return arg1.getName();
}
};
public static class Reader extends StorageReaderFolder<PreconDeck> {
public Reader(final File deckDir0) {
super(deckDir0, PreconDeck.FN_NAME_SELECTOR);
}
@Override
protected PreconDeck read(final File file) {
return getPreconDeckFromSections(FileSection.parseSections(FileUtil.readFile(file)));
}
// To be able to read "shops" section in overloads
protected PreconDeck getPreconDeckFromSections(final Map<String, List<String>> sections) {
FileSection kv = FileSection.parse(sections.get("metadata"), "=");
String imageFilename = kv.get("Image");
String description = kv.get("Description");
String deckEdition = kv.get("set");
String set = deckEdition == null || StaticData.instance().getEditions().get(deckEdition.toUpperCase()) == null ? "n/a" : deckEdition;
PreconDeck result = new PreconDeck(Deck.fromSections(sections), set, description);
result.imageFilename = imageFilename;
return result;
}
@Override
protected FilenameFilter getFileFilter() {
return DeckSerializer.DCK_FILE_FILTER;
}
}
}

View File

@@ -0,0 +1,62 @@
/*
* 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.item;
import java.util.List;
import com.google.common.base.Function;
import forge.StaticData;
import forge.card.BoosterGenerator;
import forge.card.CardEdition;
import forge.card.SealedProductTemplate;
public class TournamentPack extends OpenablePack {
/** The Constant fnFromSet. */
public static final Function<CardEdition, TournamentPack> FN_FROM_SET = new Function<CardEdition, TournamentPack>() {
@Override
public TournamentPack apply(final CardEdition arg1) {
SealedProductTemplate d = StaticData.instance().getTournamentPacks().get(arg1.getCode());
return new TournamentPack(arg1.getName(), d);
}
};
public TournamentPack(final String name0, final SealedProductTemplate boosterData) {
super(name0, boosterData);
}
public final boolean isStarterDeck() {
return contents.getSlots().get(0).getRight() < 30; // hack - getting number of commons, they are first in list
}
@Override
public final String getItemType() {
return !isStarterDeck() ? "Tournament Pack" : "Starter Deck";
}
@Override
protected List<PaperCard> generate() {
return BoosterGenerator.getBoosterPack(this.contents);
}
@Override
public final Object clone() {
return new TournamentPack(name, contents);
}
}