Support loading more information into model

This commit is contained in:
drdev
2014-03-09 05:05:16 +00:00
parent d5b516a7cb
commit ffab69b0b4
12 changed files with 1613 additions and 40 deletions

9
.gitattributes vendored
View File

@@ -189,6 +189,7 @@ forge-core/src/main/java/forge/deck/generation/DeckGeneratorBase.java -text
forge-core/src/main/java/forge/deck/generation/DeckGeneratorMonoColor.java -text
forge-core/src/main/java/forge/deck/generation/package-info.java svneol=native#text/plain
forge-core/src/main/java/forge/deck/io/DeckFileHeader.java -text
forge-core/src/main/java/forge/deck/io/DeckGroupSerializer.java -text
forge-core/src/main/java/forge/deck/io/DeckSerializer.java -text
forge-core/src/main/java/forge/deck/io/DeckStorage.java -text
forge-core/src/main/java/forge/deck/io/OldDeckFileFormatException.java -text
@@ -15450,7 +15451,6 @@ forge-gui/src/main/java/forge/control/InputQueue.java svneol=native#text/plain
forge-gui/src/main/java/forge/control/KeyboardShortcuts.java -text
forge-gui/src/main/java/forge/control/RestartUtil.java -text
forge-gui/src/main/java/forge/control/package-info.java -text
forge-gui/src/main/java/forge/deck/io/DeckGroupSerializer.java -text
forge-gui/src/main/java/forge/deck/io/DeckHtmlSerializer.java -text
forge-gui/src/main/java/forge/deck/io/DeckPreferences.java -text
forge-gui/src/main/java/forge/deck/io/OldDeckParser.java -text
@@ -16024,9 +16024,15 @@ forge-m-base/src/forge/assets/FSkinTexture.java -text
forge-m-base/src/forge/assets/FTextureImage.java -text
forge-m-base/src/forge/assets/ImageCache.java -text
forge-m-base/src/forge/assets/ImageLoader.java -text
forge-m-base/src/forge/deck/io/OldDeckParser.java -text
forge-m-base/src/forge/error/BugReporter.java -text
forge-m-base/src/forge/error/ExceptionHandler.java -text
forge-m-base/src/forge/limited/CustomLimited.java -text
forge-m-base/src/forge/model/CardBlock.java -text
forge-m-base/src/forge/model/CardCollections.java -text
forge-m-base/src/forge/model/FModel.java -text
forge-m-base/src/forge/model/MetaSet.java -text
forge-m-base/src/forge/model/UnOpenedMeta.java -text
forge-m-base/src/forge/player/LobbyPlayerHuman.java -text
forge-m-base/src/forge/player/PlayerControllerHuman.java -text
forge-m-base/src/forge/screens/FScreen.java -text
@@ -16060,6 +16066,7 @@ forge-m-base/src/forge/toolbox/FOptionPane.java -text
forge-m-base/src/forge/toolbox/FOverlay.java -text
forge-m-base/src/forge/toolbox/FProgressBar.java -text
forge-m-base/src/forge/toolbox/FScrollPane.java -text
forge-m-base/src/forge/toolbox/GuiChoose.java -text
forge-m-base/src/forge/utils/Constants.java -text
forge-m-base/src/forge/utils/ForgePreferences.java -text
forge-m-base/src/forge/utils/ForgeProfileProperties.java -text

View File

@@ -0,0 +1,275 @@
/*
* 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 forge.deck.Deck;
import forge.deck.DeckGroup;
import forge.toolbox.FOptionPane;
import forge.util.FileSection;
import forge.util.FileUtil;
import forge.util.storage.IStorage;
import forge.utils.Constants;
import org.apache.commons.lang3.tuple.ImmutablePair;
import org.apache.commons.lang3.tuple.MutablePair;
import org.apache.commons.lang3.tuple.Pair;
import java.io.File;
import java.io.FilenameFilter;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.TreeMap;
/**
* TODO: Write javadoc for this type.
*
*/
public class OldDeckParser {
/** Constant <code>BDKFileFilter</code>. */
public static final FilenameFilter BDK_FILE_FILTER = new FilenameFilter() {
@Override
public boolean accept(final File dir, final String name) {
return name.endsWith(".bdk");
}
};
/**
* TODO: Write javadoc for Constructor.
*
* @param file the file
* @param constructed2 the constructed2
* @param draft2 the draft2
* @param sealed2 the sealed2
* @param cube2 the cube2
*/
public OldDeckParser(final IStorage<Deck> constructed2, final IStorage<DeckGroup> draft2,
final IStorage<DeckGroup> sealed2, final IStorage<Deck> cube2) {
this.deckDir = new File(Constants.DECK_BASE_DIR);
this.sealed = sealed2;
this.constructed = constructed2;
this.cube = cube2;
this.draft = draft2;
}
/**
* Gets the sealed.
*
* @return the sealed
*/
protected final IStorage<DeckGroup> getSealed() {
return this.sealed;
}
/**
* Gets the constructed.
*
* @return the constructed
*/
protected final IStorage<Deck> getConstructed() {
return this.constructed;
}
/**
* Gets the draft.
*
* @return the draft
*/
protected final IStorage<DeckGroup> getDraft() {
return this.draft;
}
/**
* Gets the cube.
*
* @return the cube
*/
protected final IStorage<Deck> getCube() {
return this.cube;
}
/**
* Gets the deck dir.
*
* @return the deck dir
*/
protected final File getDeckDir() {
return this.deckDir;
}
private final IStorage<DeckGroup> sealed;
private final IStorage<Deck> constructed;
private final IStorage<DeckGroup> draft;
private final IStorage<Deck> cube;
private final File deckDir;
/**
* TODO: Write javadoc for this method.
*/
public void tryParse() {
this.convertConstructedAndSealed();
this.convertDrafts();
}
private void convertDrafts() {
for (final File f : this.deckDir.listFiles(OldDeckParser.BDK_FILE_FILTER)) {
boolean gotError = false;
final Deck human = DeckSerializer.fromFile(new File(f, "0.dck"));
final DeckGroup d = new DeckGroup(human.getName());
d.setHumanDeck(human);
for (int i = 1; i < DeckGroupSerializer.MAX_DRAFT_PLAYERS; i++) {
final Deck nextAi = DeckSerializer.fromFile(new File(f, i + ".dck"));
if (nextAi == null) {
gotError = true;
break;
}
d.addAiDeck(nextAi);
}
boolean mayDelete = !gotError;
if (!gotError) {
this.draft.add(d);
} else {
final String msg = String.format("Draft '%s' lacked some decks.%n%nShould it be deleted?");
mayDelete = FOptionPane.showConfirmDialog(msg, "Draft loading error");
}
if (mayDelete) {
for (final File f1 : f.listFiles()) {
f1.delete();
}
f.delete();
}
}
}
private void convertConstructedAndSealed() {
boolean allowDeleteUnsupportedConstructed = false;
final Map<String, Pair<DeckGroup, MutablePair<File, File>>> sealedDecks = new TreeMap<String, Pair<DeckGroup, MutablePair<File, File>>>(
String.CASE_INSENSITIVE_ORDER);
for (final File f : this.deckDir.listFiles(DeckStorage.DCK_FILE_FILTER)) {
boolean importedOk = false;
final List<String> fileLines = FileUtil.readFile(f);
final Map<String, List<String>> sections = FileSection.parseSections(fileLines);
final DeckFileHeader dh = DeckSerializer.readDeckMetadata(sections);
String name = dh.getName();
if (dh.isCustomPool()) {
try {
this.cube.add(DeckSerializer.fromSections(sections));
importedOk = true;
}
catch (final NoSuchElementException ex) {
if (!allowDeleteUnsupportedConstructed) {
final String msg = String
.format("Can not convert deck '%s' for some unsupported cards it contains. %n%s%n%nMay Forge delete all such decks?",
name, ex.getMessage());
allowDeleteUnsupportedConstructed = FOptionPane.showConfirmDialog(msg, "Problem converting decks");
}
}
if (importedOk || allowDeleteUnsupportedConstructed) {
f.delete();
}
continue;
}
switch (dh.getDeckType()) {
case Constructed:
try {
this.constructed.add(DeckSerializer.fromSections(sections));
importedOk = true;
} catch (final NoSuchElementException ex) {
if (!allowDeleteUnsupportedConstructed) {
final String msg = String
.format("Can not convert deck '%s' for some unsupported cards it contains. %n%s%n%nMay Forge delete all such decks?",
name, ex.getMessage());
allowDeleteUnsupportedConstructed = FOptionPane.showConfirmDialog(msg, "Problem converting decks");
}
}
if (importedOk || allowDeleteUnsupportedConstructed) {
f.delete();
}
break;
case Limited:
name = name.startsWith("AI_") ? name.replace("AI_", "") : name;
Pair<DeckGroup, MutablePair<File, File>> stored = sealedDecks.get(name);
if (null == stored) {
stored = ImmutablePair.of(new DeckGroup(name), MutablePair.of((File) null, (File) null));
}
final Deck deck = DeckSerializer.fromSections(sections);
if (dh.isIntendedForAi()) {
stored.getLeft().addAiDeck(deck);
stored.getRight().setRight(f);
} else {
stored.getLeft().setHumanDeck(deck);
stored.getRight().setLeft(f);
}
if ((stored.getLeft().getHumanDeck() != null) && !stored.getLeft().getAiDecks().isEmpty()) {
// have both parts of sealed deck, may convert
this.sealed.add(stored.getLeft());
stored.getRight().getLeft().delete();
stored.getRight().getRight().delete();
// there stay only orphans
sealedDecks.remove(name);
} else {
sealedDecks.put(name, stored);
}
break;
default:
break;
}
}
// advise to kill orphaned decks
if (!sealedDecks.isEmpty()) {
final StringBuilder sb = new StringBuilder();
for (final Pair<DeckGroup, MutablePair<File, File>> s : sealedDecks.values()) {
final String missingPart = s.getRight().getLeft() == null ? "human" : "computer";
sb.append(String.format("Sealed deck '%s' has no matching '%s' deck.%n", s.getKey().getName(),
missingPart));
}
sb.append(System.getProperty("line.separator"));
sb.append("May Forge delete these decks?");
if (FOptionPane.showConfirmDialog(sb.toString(), "Some of your sealed decks are orphaned")) {
for (final Pair<DeckGroup, MutablePair<File, File>> s : sealedDecks.values()) {
if (s.getRight().getLeft() != null) {
s.getRight().getLeft().delete();
}
if (s.getRight().getRight() != null) {
s.getRight().getRight().delete();
}
}
}
}
}
/**
* @return the deckDir
*/
}

View File

@@ -0,0 +1,180 @@
/*
* 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.limited;
import forge.card.CardEdition;
import forge.deck.Deck;
import forge.deck.DeckBase;
import forge.item.PaperCard;
import forge.item.SealedProduct;
import forge.model.FModel;
import forge.util.FileSection;
import forge.util.ItemPool;
import forge.util.TextUtil;
import forge.util.storage.IStorage;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.ImmutablePair;
import org.apache.commons.lang3.tuple.Pair;
import java.util.ArrayList;
import java.util.List;
/**
* <p>
* CustomDraft class.
* </p>
*
* @author Forge
* @version $Id: CustomLimited.java 24769 2014-02-09 13:56:04Z Hellfish $
*/
public class CustomLimited extends DeckBase {
private final SealedProduct.Template tpl;
/**
* TODO: Write javadoc for Constructor.
*
* @param name0 the name0
* @param slots
*/
public CustomLimited(final String name0, List<Pair<String, Integer>> slots) {
super(name0);
tpl = new SealedProduct.Template(slots);
}
private static final long serialVersionUID = 7435640939026612173L;
/** The Num packs. */
private int numPacks = 3;
private transient ItemPool<PaperCard> cardPool;
/** The Land set code. */
private String landSetCode = CardEdition.Predicates.getRandomSetWithAllBasicLands(FModel.getMagicDb().getEditions()).getCode();
private boolean singleton;
/*
* (non-Javadoc)
*
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
return this.getName();
}
@Override
public String getItemType() {
return "Limited deck";
}
/**
* Parses the.
*
* @param dfData the df data
* @param cubes the cubes
* @return the custom limited
*/
public static CustomLimited parse(final List<String> dfData, final IStorage<Deck> cubes) {
final FileSection data = FileSection.parse(dfData, ":");
List<Pair<String, Integer>> slots = new ArrayList<Pair<String,Integer>>();
String boosterData = data.get("Booster");
if(StringUtils.isNotEmpty(boosterData)){
final String[] booster = TextUtil.splitWithParenthesis(boosterData, ',');
for(String slotDesc : booster) {
String[] kv = TextUtil.splitWithParenthesis(slotDesc, ' ', 2);
slots.add(ImmutablePair.of(kv[1], Integer.parseInt(kv[0])));
}
} else
slots = SealedProduct.Template.genericBooster.getSlots();
final CustomLimited cd = new CustomLimited(data.get("Name"), slots);
cd.landSetCode = data.get("LandSetCode");
cd.numPacks = data.getInt("NumPacks");
cd.singleton = data.getBoolean("Singleton");
final Deck deckCube = cubes.get(data.get("DeckFile"));
cd.cardPool = deckCube == null ? ItemPool.createFrom(FModel.getMagicDb().getCommonCards().getUniqueCards(), PaperCard.class) : deckCube.getMain();
return cd;
}
/**
* Gets the num packs.
*
* @return the numPacks
*/
public int getNumPacks() {
return this.numPacks;
}
/**
* Sets the num packs.
*
* @param numPacksIn
* the numPacks to set
*/
public void setNumPacks(final int numPacksIn) {
this.numPacks = numPacksIn;
}
/**
* Gets the land set code.
*
* @return the landSetCode
*/
public String getLandSetCode() {
return this.landSetCode;
}
/*
* (non-Javadoc)
*
* @see forge.item.CardCollectionBase#getCardPool()
*/
public ItemPool<PaperCard> getCardPool() {
return this.cardPool;
}
/*
* (non-Javadoc)
*
* @see forge.deck.DeckBase#getInstance(java.lang.String)
*/
@Override
protected DeckBase newInstance(final String name0) {
return new CustomLimited(name0, tpl.getSlots());
}
/**
* TODO: Write javadoc for this method.
* @return
*/
public SealedProduct.Template getSealedProductTemplate() {
return tpl;
}
public boolean isSingleton() {
return singleton;
}
}

View File

@@ -0,0 +1,302 @@
/*
* 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.model;
import com.google.common.base.Function;
import com.google.common.base.Predicate;
import forge.card.CardEdition;
import forge.card.IUnOpenedProduct;
import forge.card.UnOpenedProduct;
import forge.item.IPaperCard;
import forge.item.PaperCard;
import forge.util.TextUtil;
import forge.util.storage.StorageReaderFile;
import org.apache.commons.lang3.StringUtils;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
// import forge.deck.Deck;
/**
* This is a CardBlock class.
*/
public final class CardBlock implements Comparable<CardBlock> {
private static final CardEdition[] EMPTY_SET_ARRAY = new CardEdition[] {};
private final int orderNum;
private final String name;
private final CardEdition[] sets;
private final Map<String, MetaSet> metaSets = new TreeMap<String, MetaSet>();
private final CardEdition landSet;
private final int cntBoostersDraft;
private final int cntBoostersSealed;
private Predicate<PaperCard> filter = null;
/**
* Instantiates a new card block.
*
* @param index
* the index
* @param name
* the name
* @param sets
* the sets
* @param metas
* the included meta-sets
* @param landSet
* the land set
* @param cntBoostersDraft
* the cnt boosters draft
* @param cntBoostersSealed
* the cnt boosters sealed
*/
public CardBlock(final int index, final String name, final List<CardEdition> sets, final List<MetaSet> metas,
final CardEdition landSet, final int cntBoostersDraft, final int cntBoostersSealed) {
this.orderNum = index;
this.name = name;
this.sets = sets.toArray(CardBlock.EMPTY_SET_ARRAY);
for(MetaSet m : metas) {
this.metaSets.put(m.getCode(), m);
}
this.landSet = landSet;
this.cntBoostersDraft = cntBoostersDraft;
this.cntBoostersSealed = cntBoostersSealed;
}
/**
* Gets the name.
*
* @return the name
*/
public String getName() {
return this.name;
}
/**
* Gets the sets.
*
* @return the sets
*/
public CardEdition[] getSets() {
return this.sets;
}
/**
* Gets the land set.
*
* @return the land set
*/
public CardEdition getLandSet() {
return this.landSet;
}
/**
* Gets the cnt boosters draft.
*
* @return the cnt boosters draft
*/
public int getCntBoostersDraft() {
return this.cntBoostersDraft;
}
/**
* Gets the cnt boosters sealed.
*
* @return the cnt boosters sealed
*/
public int getCntBoostersSealed() {
return this.cntBoostersSealed;
}
/**
* Gets the filter.
*
* @return the filter
*/
public Predicate<PaperCard> getFilter() {
if (this.filter == null) {
this.filter = this.buildFilter();
}
return this.filter;
}
private Predicate<PaperCard> buildFilter() {
final List<String> setCodes = new ArrayList<String>();
for (final CardEdition set : this.sets) {
setCodes.add(set.getCode());
}
return IPaperCard.Predicates.printedInSets(setCodes, true);
}
/*
* (non-Javadoc)
*
* @see java.lang.Object#hashCode()
*/
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = (prime * result) + ((this.landSet == null) ? 0 : this.landSet.hashCode());
result = (prime * result) + ((this.name == null) ? 0 : this.name.hashCode());
return result;
}
/*
* (non-Javadoc)
*
* @see java.lang.Object#equals(java.lang.Object)
*/
@Override
public boolean equals(final Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (this.getClass() != obj.getClass()) {
return false;
}
final CardBlock other = (CardBlock) obj;
if (!this.landSet.equals(other.landSet)) {
return false;
}
if (!this.name.equals(other.name)) {
return false;
}
return true;
}
/*
* (non-Javadoc)
*
* @see java.lang.Comparable#compareTo(java.lang.Object)
*/
@Override
public int compareTo(final CardBlock o) {
return this.orderNum - o.orderNum;
}
/*
* (non-Javadoc)
*
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
if (this.metaSets.isEmpty() && this.sets.length < 1) {
return this.name + " (empty)";
} else if (this.metaSets.size() + this.getNumberSets() < 2) {
return this.name + " (set)";
}
return this.name + " (block)";
}
public static final Function<CardBlock, String> FN_GET_NAME = new Function<CardBlock, String>() {
@Override
public String apply(CardBlock arg1) {
return arg1.getName();
}
};
public static class Reader extends StorageReaderFile<CardBlock> {
private final CardEdition.Collection editions;
/**
* TODO: Write javadoc for Constructor.
* @param pathname
* @param keySelector0
*/
public Reader(String pathname, CardEdition.Collection editions0) {
super(pathname, CardBlock.FN_GET_NAME);
editions = editions0;
}
/* (non-Javadoc)
* @see forge.util.StorageReaderFile#read(java.lang.String)
*/
@Override
protected CardBlock read(String line, int i) {
final String[] sParts = TextUtil.splitWithParenthesis(line.trim(), ',', 3);
String name = sParts[0];
String[] numbers = sParts[1].trim().split("/");
int draftBoosters = StringUtils.isNumeric(numbers[0]) ? Integer.parseInt(numbers[0]) : 0;
int sealedBoosters = StringUtils.isNumeric(numbers[1]) ? Integer.parseInt(numbers[1]) : 0;
CardEdition landSet = editions.getEditionByCodeOrThrow(numbers[2]);
List<CardEdition> sets = new ArrayList<CardEdition>();
List<MetaSet> metas = new ArrayList<MetaSet>();
String[] setNames = TextUtil.splitWithParenthesis(sParts[2], ' ' );
for(final String set : setNames ) {
if(set.startsWith("Meta-")) {
String metaSpec = set.substring(5);
boolean noDraft = metaSpec.startsWith("NoDraft-");
if( noDraft ) metaSpec = metaSpec.substring(8);
metas.add(new MetaSet(metaSpec, noDraft));
} else {
sets.add(editions.getEditionByCodeOrThrow(set));
}
}
return new CardBlock(i+1, name, sets, metas, landSet, draftBoosters, sealedBoosters);
}
}
/**
* The number of normal sets in the block.
*
* @return int, number of sets.
*/
public int getNumberSets() {
if (sets == null || sets.length < 1) {
return 0;
}
else {
return sets.length;
}
}
public Iterable<String> getMetaSetNames() {
return metaSets.keySet();
}
public MetaSet getMetaSet(String key) {
return metaSets.get(key);
}
/**
* Tries to create a booster for the selected meta-set code.
*
* @param code
* String, the MetaSet code
* @return UnOpenedProduct, the created booster.
*/
public IUnOpenedProduct getBooster(final String code) {
MetaSet ms = metaSets.get(code);
return ms == null ? new UnOpenedProduct(FModel.getMagicDb().getBoosters().get(code)) : ms.getBooster();
}
}

View File

@@ -0,0 +1,129 @@
/*
* 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.model;
import forge.deck.Deck;
import forge.deck.DeckGroup;
import forge.deck.io.DeckGroupSerializer;
import forge.deck.io.DeckStorage;
import forge.deck.io.OldDeckParser;
import forge.util.storage.IStorage;
import forge.util.storage.StorageImmediatelySerialized;
import forge.utils.Constants;
import org.apache.commons.lang3.time.StopWatch;
import java.io.File;
/**
* Holds editable maps of decks saved to disk. Adding or removing items to(from)
* such map turns into immediate file update
*/
public class CardCollections {
private final IStorage<Deck> constructed;
private final IStorage<DeckGroup> draft;
private final IStorage<DeckGroup> sealed;
private final IStorage<Deck> cube;
private final IStorage<Deck> scheme;
private final IStorage<Deck> plane;
private final IStorage<Deck> commander;
/**
* TODO: Write javadoc for Constructor.
*
* @param file the file
*/
public CardCollections() {
StopWatch sw = new StopWatch();
sw.start();
this.constructed = new StorageImmediatelySerialized<Deck>("Constructed decks", new DeckStorage(new File(Constants.DECK_CONSTRUCTED_DIR), true), true);
this.draft = new StorageImmediatelySerialized<DeckGroup>("Draft deck sets", new DeckGroupSerializer(new File(Constants.DECK_DRAFT_DIR)));
this.sealed = new StorageImmediatelySerialized<DeckGroup>("Sealed deck sets", new DeckGroupSerializer(new File(Constants.DECK_SEALED_DIR)));
this.cube = new StorageImmediatelySerialized<Deck>("Cubes", new DeckStorage(new File(Constants.DECK_CUBE_DIR)));
this.scheme = new StorageImmediatelySerialized<Deck>("Archenemy decks", new DeckStorage(new File(Constants.DECK_SCHEME_DIR)));
this.plane = new StorageImmediatelySerialized<Deck>("Planechase decks", new DeckStorage(new File(Constants.DECK_PLANE_DIR)));
this.commander = new StorageImmediatelySerialized<Deck>("Commander decks", new DeckStorage(new File(Constants.DECK_COMMANDER_DIR)));
sw.stop();
System.out.printf("Read decks (%d ms): %d constructed, %d sealed, %d draft, %d cubes, %d scheme, %d planar, %d commander.%n", sw.getTime(), constructed.size(), sealed.size(), draft.size(), cube.size(), scheme.size(), plane.size(),commander.size());
// int sum = constructed.size() + sealed.size() + draft.size() + cube.size() + scheme.size() + plane.size();
// FSkin.setProgessBarMessage(String.format("Loaded %d decks in %f sec", sum, sw.getTime() / 1000f ));
// remove this after most people have been switched to new layout
final OldDeckParser oldParser = new OldDeckParser(this.constructed, this.draft, this.sealed, this.cube);
oldParser.tryParse();
}
/**
* Gets the constructed.
*
* @return the constructed
*/
public final IStorage<Deck> getConstructed() {
return this.constructed;
}
/**
* Gets the draft.
*
* @return the draft
*/
public final IStorage<DeckGroup> getDraft() {
return this.draft;
}
/**
* Gets the cubes.
*
* @return the cubes
*/
public final IStorage<Deck> getCubes() {
return this.cube;
}
/**
* Gets the sealed.
*
* @return the sealed
*/
public IStorage<DeckGroup> getSealed() {
return this.sealed;
}
/**
* TODO: Write javadoc for this method.
* @return
*/
public IStorage<Deck> getScheme() {
return this.scheme;
}
/**
* @return the plane
*/
public IStorage<Deck> getPlane() {
return plane;
}
/**
* @return the plane
*/
public IStorage<Deck> getCommander() {
return commander;
}
}

View File

@@ -25,6 +25,8 @@ import forge.game.GameFormat;
import forge.game.card.CardUtil;
import forge.toolbox.FProgressBar;
import forge.util.FileUtil;
import forge.util.storage.IStorage;
import forge.util.storage.StorageBase;
import forge.utils.Constants;
import forge.utils.ForgePreferences;
@@ -53,15 +55,15 @@ public class FModel {
private static ForgePreferences preferences;
// Someone should take care of 2 gauntlets here
/*private static GauntletData gauntletData;
private static GauntletMini gauntlet;
//private static GauntletData gauntletData;
//private static GauntletMini gauntlet;
private static QuestController quest;
//private static QuestController quest;
private static CardCollections decks;
private static IStorage<CardBlock> blocks;
private static IStorage<CardBlock> fantasyBlocks;
private static IStorage<QuestWorld> worlds;*/
//private static IStorage<QuestWorld> worlds;
private static GameFormat.Collection formats;
public static void initialize(final FProgressBar progressBar) {
@@ -138,18 +140,18 @@ public class FModel {
}
formats = new GameFormat.Collection(new GameFormat.Reader(new File(Constants.BLOCK_DATA_DIR + "formats.txt")));
/*blocks = new StorageBase<CardBlock>("Block definitions", new CardBlock.Reader(Constants.BLOCK_DATA_DIR + "blocks.txt", magicDb.getEditions()));
questPreferences = new QuestPreferences();
gauntletData = new GauntletData();
blocks = new StorageBase<CardBlock>("Block definitions", new CardBlock.Reader(Constants.BLOCK_DATA_DIR + "blocks.txt", magicDb.getEditions()));
//questPreferences = new QuestPreferences();
//gauntletData = new GauntletData();
fantasyBlocks = new StorageBase<CardBlock>("Custom blocks", new CardBlock.Reader(Constants.BLOCK_DATA_DIR + "fantasyblocks.txt", magicDb.getEditions()));
worlds = new StorageBase<QuestWorld>("Quest worlds", new QuestWorld.Reader(Constants.QUEST_WORLD_DIR + "worlds.txt"));*/
//worlds = new StorageBase<QuestWorld>("Quest worlds", new QuestWorld.Reader(Constants.QUEST_WORLD_DIR + "worlds.txt"));
loadDynamicGamedata();
progressBar.setDescription("Loading decks");
/*decks = new CardCollections();
quest = new QuestController();*/
decks = new CardCollections();
//quest = new QuestController();
//preload AI profiles
AiProfileUtil.loadAllProfiles(Constants.AI_PROFILE_DIR);
@@ -272,23 +274,23 @@ public class FModel {
return preferences;
}
/*public static IStorage<CardBlock> getBlocks() {
public static IStorage<CardBlock> getBlocks() {
return blocks;
}
public static QuestPreferences getQuestPreferences() {
/*public static QuestPreferences getQuestPreferences() {
return questPreferences;
}
public static GauntletData getGauntletData() {
return gauntletData;
}
}*/
public static CardCollections getDecks() {
return decks;
}
public static IStorage<QuestWorld> getWorlds() {
/*public static IStorage<QuestWorld> getWorlds() {
return worlds;
}*/
@@ -296,6 +298,10 @@ public class FModel {
return formats;
}
public static IStorage<CardBlock> getFantasyBlocks() {
return fantasyBlocks;
}
/**
* Finalizer, generally should be avoided, but here closes the log file
* stream and resets the system output streams.
@@ -308,13 +314,9 @@ public class FModel {
/*public static void setGauntletData(GauntletData data0) {
gauntletData = data0;
}
}*/
public static IStorage<CardBlock> getFantasyBlocks() {
return fantasyBlocks;
}
public static GauntletMini getGauntletMini() {
/*public static GauntletMini getGauntletMini() {
if (gauntlet == null) {
gauntlet = new GauntletMini();
}

View File

@@ -0,0 +1,214 @@
/*
* 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.model;
import com.google.common.base.Predicate;
import forge.card.IUnOpenedProduct;
import forge.card.UnOpenedProduct;
import forge.item.IPaperCard;
import forge.item.PaperCard;
import forge.item.SealedProduct;
import forge.limited.CustomLimited;
import forge.util.FileUtil;
import java.io.File;
import java.util.List;
/**
* The class MetaSet. This class is used to define 'special'
* sets within a (fantasy) block, like custom sets (cubes),
* combination sets (sub-blocks), and full cardpool.
*
* NOTE: The format of a MetaSet definition is as follows
* (in a blocks definition file):
*
* "metaX A/B/C"
*
* where "X" is an integer from 0...8 (just like for sets)
*
* "A" is either "cube", "meta", "full", "choose1", "random1",
* "set", "pack", or "combo".
*
* "full" uses all available cards for this booster, just like
* the full cardpool option. The values of "B" and "C" are not
* relevant ("B" is not used at all, and the displayed name is
* always "*FULL").
*
* "meta" uses a cardpool that is combined from several
* editions. The parameter "B" is a list of 3-letter
* edition codes, separated with commas, e.g.
* "2ED,ARN,ATQ". The parameter "C" is the name
* that is displayed for this meta-booster in the
* set selection menu.
*
* "cube" uses a previously defined custom sealed deck
* deck cube as the cardpool for this booster. The cube
* definition file must be in res/sealed/ and have a
* ".sealed" extension. The related .dck file must be
* in the res/decks/cube directory.
* "B" is the name of the cube definition file without
* the ".sealed" extension, e.g. "juzamjedi".
* "C" is the name that is displayed for this meta-booster
* in the set selection menu.
*
* The new types added after beta 1.2.14:
*
* "choose1": define several metasets in a semicolon-separated (;)
* list in value B, the player will choose one of them.
*
* "random1": like choose1, except that the player will get a
* random pack.
*
* "combo": define several metasets in a semicolon-separated (;)
* list in value B, the booster will be based on the combined
* cardpool of all these. Note that if one of the metasets is
* a "full", the rest are irrelevant.
*
* "booster": generate a single booster based on value B set. (You
* should use this only for combo, choose1 and random1 metasets,
* otherwise use normal Sets instead of MetaSets in the block
* definition!)
*
* "pack": like set, but attempts to generate a starter pack instead
* of a booster. If starter packs are not available for value B set,
* a booster is generated instead.
*
*/
public class MetaSet {
private enum MetaSetType {
Full("F", "All cards"),
Cube("C", "Cube"),
JoinedSet("J", "Joined set"),
Choose("Select", "Choose from list"),
Combo("All", "Combined booster"),
Random("Any", "Randomly selected"),
Booster("B", "Booster"),
SpecialBooster("S", "Special Booster"),
Pack("T", "Tournament/Starter");
private final String shortHand;
public final String descriptiveName;
private MetaSetType(String shortname, String descName) {
shortHand = shortname;
descriptiveName = descName;
}
public static MetaSetType smartValueOf(String trim) {
for(MetaSetType mt : MetaSetType.values()) {
if( mt.name().equalsIgnoreCase(trim) || mt.shortHand.equalsIgnoreCase(trim))
return mt;
}
throw new IllegalArgumentException(trim + " not recognized as Meta Set");
}
}
private final MetaSetType type;
private final String data;
private final String code;
private final boolean draftable;
// private BoosterGenerator boosterGen;
/**
* The constructor. A new MetaSet is currently only instantiated in CardBlock.java
* when CardBlock information is read.
*
* @param creationString
* a {@link java.lang.String} object.
*/
public MetaSet(final String creationString, boolean canDraft) {
int idxFirstPar = creationString.indexOf('(');
int idxLastPar = creationString.lastIndexOf(')');
draftable = canDraft;
type = MetaSetType.smartValueOf(creationString.substring(0, idxFirstPar).trim());
data = creationString.substring(idxFirstPar + 1, idxLastPar);
String description = creationString.substring(idxLastPar + 1);
code = description + "\u00A0(" + type.descriptiveName + ")"; // u00A0 (nbsp) will not be equal to simple space
}
/**
* Return the code.
*
* @return
* String, code
*/
public final String getCode() {
return code;
}
/**
*
* Attempt to get a booster.
*
* @return UnOpenedProduct, the generated booster.
*/
public IUnOpenedProduct getBooster() {
switch(type) {
case Full:
return new UnOpenedProduct(SealedProduct.Template.genericBooster);
case Booster:
return new UnOpenedProduct(FModel.getMagicDb().getBoosters().get(data));
case SpecialBooster:
return new UnOpenedProduct(FModel.getMagicDb().getSpecialBoosters().get(data));
case Pack:
return new UnOpenedProduct(FModel.getMagicDb().getTournamentPacks().get(data));
case JoinedSet:
Predicate<PaperCard> predicate = IPaperCard.Predicates.printedInSets(data.split(" "));
return new UnOpenedProduct(SealedProduct.Template.genericBooster, predicate);
case Choose: return UnOpenedMeta.choose(data);
case Random: return UnOpenedMeta.random(data);
case Combo: return UnOpenedMeta.selectAll(data);
case Cube:
final File dFolder = new File("res/sealed/");
if (!dFolder.exists()) {
throw new RuntimeException("GenerateSealed : folder not found -- folder is " + dFolder.getAbsolutePath());
}
if (!dFolder.isDirectory()) {
throw new RuntimeException("GenerateSealed : not a folder -- " + dFolder.getAbsolutePath());
}
List<String> dfData = FileUtil.readFile("res/sealed/" + data + ".sealed");
final CustomLimited myCube = CustomLimited.parse(dfData, FModel.getDecks().getCubes());
SealedProduct.Template fnPick = myCube.getSealedProductTemplate();
return new UnOpenedProduct(fnPick, myCube.getCardPool());
default: return null;
}
}
@Override
public String toString() {
return code;
}
public boolean isDraftable() {
return draftable;
}
}

View File

@@ -0,0 +1,126 @@
/*
* 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.model;
import forge.card.IUnOpenedProduct;
import forge.item.PaperCard;
import forge.toolbox.GuiChoose;
import forge.util.MyRandom;
import forge.util.TextUtil;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
/**
* This type extends UnOpenedProduct to support booster choice or random boosters
* in sealed deck games. See MetaSet.java for further information.
*/
public class UnOpenedMeta implements IUnOpenedProduct {
private enum JoinOperation {
RandomOne,
ChooseOne,
SelectAll,
}
private final ArrayList<MetaSet> metaSets;
private final JoinOperation operation;
private final Random generator = MyRandom.getRandom();
/**
* Constructor for UnOpenedMeta.
* @param creationString
* String, is parsed for MetaSet info.
* @param choose
* sets the random/choice status.
*/
private UnOpenedMeta(final String creationString, final JoinOperation op) {
metaSets = new ArrayList<MetaSet>();
operation = op;
for (String m : TextUtil.splitWithParenthesis(creationString, ';')) {
metaSets.add(new MetaSet(m, true));
}
}
/**
* Open the booster pack, return contents.
* @return List, list of cards.
*/
@Override
public List<PaperCard> get() {
return this.open(true, false);
}
/**
* Like open, can define whether is human or not.
* @param isHuman
* boolean, is human player?
* @param partialities
* known partialities for the AI.
* @return List, list of cards.
*/
public List<PaperCard> open(final boolean isHuman, final boolean allowCancel) {
if (metaSets.isEmpty()) {
throw new RuntimeException("Empty UnOpenedMetaset, cannot generate booster.");
}
switch (operation) {
case ChooseOne:
if (isHuman) {
final MetaSet ms;
if (allowCancel) {
ms = GuiChoose.oneOrNone("Choose Booster", metaSets);
if (ms == null) {
return null;
}
}
else {
ms = GuiChoose.one("Choose Booster", metaSets);
}
return ms.getBooster().get();
}
case RandomOne: // AI should fall though here from the case above
int selected = generator.nextInt(metaSets.size());
final IUnOpenedProduct newBooster = metaSets.get(selected).getBooster();
return newBooster.get();
case SelectAll:
List<PaperCard> allCards = new ArrayList<PaperCard>();
for (MetaSet ms : metaSets) {
allCards.addAll(ms.getBooster().get());
}
return allCards;
}
throw new IllegalStateException("Got wrong operation type in unopenedMeta - execution should never reach this point");
}
public static UnOpenedMeta choose(String desc) {
return new UnOpenedMeta(desc, JoinOperation.ChooseOne);
}
public static UnOpenedMeta random(String desc) {
return new UnOpenedMeta(desc, JoinOperation.RandomOne);
}
public static UnOpenedMeta selectAll(String desc) {
return new UnOpenedMeta(desc, JoinOperation.SelectAll);
}
}

View File

@@ -1,10 +1,11 @@
package forge.player;
import forge.ai.PlayerControllerAi;
import forge.game.Game;
import forge.game.player.LobbyPlayer;
import forge.game.player.Player;
import forge.game.player.PlayerController;
import forge.model.FModel;
import forge.utils.ForgePreferences.FPref;
public class LobbyPlayerHuman extends LobbyPlayer {
public LobbyPlayerHuman(String name) {
@@ -18,17 +19,18 @@ public class LobbyPlayerHuman extends LobbyPlayer {
@Override
public PlayerController createControllerFor(Player human) {
return new PlayerControllerAi(human.getGame(), human, this); //TODO new PlayerControllerHuman(human.getGame(), human, this);
return new PlayerControllerHuman(human.getGame(), human, this);
}
@Override
public Player createIngamePlayer(Game game) { //TODO
Player player = new Player(/*GuiDisplayUtil.personalizeHuman(*/getName()/*)*/, game);
player.setFirstController(new PlayerControllerAi(game, player, this)/*new PlayerControllerHuman(game, player, this)*/);
player.setFirstController(new PlayerControllerHuman(game, player, this));
/*if (ForgePreferences.DEV_MODE && Singletons.getModel().getPreferences().getPrefBoolean(FPref.DEV_UNLIMITED_LAND)) {
if (FModel.getPreferences().getPrefBoolean(FPref.DEV_MODE_ENABLED) &&
FModel.getPreferences().getPrefBoolean(FPref.DEV_UNLIMITED_LAND)) {
player.canCheatPlayUnlimitedLands = true;
}*/
}
return player;
}

View File

@@ -1,20 +1,16 @@
package forge.player;
/*import com.google.common.base.Predicate;
import com.google.common.base.Predicate;
import com.google.common.collect.Multimap;
import forge.card.ColorSet;
import forge.card.MagicColor;
import forge.card.mana.ManaCost;
import forge.card.mana.ManaCostShard;
import forge.deck.CardPool;
import forge.deck.Deck;
import forge.deck.DeckSection;
import forge.game.Game;
import forge.game.GameEntity;
import forge.game.GameObject;
import forge.game.GameType;
import forge.game.ability.effects.CharmEffect;
import forge.game.card.Card;
import forge.game.card.CardShields;
import forge.game.card.CounterType;
@@ -23,7 +19,6 @@ import forge.game.cost.Cost;
import forge.game.cost.CostPart;
import forge.game.cost.CostPartMana;
import forge.game.mana.Mana;
import forge.game.phase.PhaseType;
import forge.game.player.LobbyPlayer;
import forge.game.player.Player;
import forge.game.player.PlayerActionConfirmMode;
@@ -35,25 +30,20 @@ import forge.game.spellability.SpellAbilityStackInstance;
import forge.game.spellability.TargetChoices;
import forge.game.trigger.Trigger;
import forge.game.trigger.WrappedAbility;
import forge.game.zone.Zone;
import forge.game.zone.ZoneType;
import forge.item.PaperCard;
import forge.util.Lang;
import forge.util.TextUtil;
import org.apache.commons.lang3.tuple.ImmutablePair;
import org.apache.commons.lang3.tuple.Pair;
import java.awt.event.KeyEvent;
import java.awt.event.MouseEvent;
import java.util.*;
*//**
/**
* A prototype for player controller class
*
* Handles phase skips for now.
*//*
*/
public class PlayerControllerHuman extends PlayerController {
public PlayerControllerHuman(Game game0, Player p, LobbyPlayer lp) {
super(game0, p, lp);
@@ -523,4 +513,4 @@ public class PlayerControllerHuman extends PlayerController {
// TODO Auto-generated method stub
return null;
}
}*/
}

View File

@@ -0,0 +1,346 @@
package forge.toolbox;
import com.google.common.base.Function;
import com.google.common.collect.Iterables;
import forge.game.card.Card;
import org.apache.commons.lang3.StringUtils;
import java.util.*;
/**
* TODO: Write javadoc for this type.
*
*/
public class GuiChoose {
/**
* Convenience for getChoices(message, 0, 1, choices).
*
* @param <T>
* is automatically inferred.
* @param message
* a {@link java.lang.String} object.
* @param choices
* a T object.
* @return null if choices is missing, empty, or if the users' choices are
* empty; otherwise, returns the first item in the List returned by
* getChoices.
* @see #getChoices(String, int, int, Object...)
*/
public static <T> T oneOrNone(final String message, final T[] choices) {
if ((choices == null) || (choices.length == 0)) {
return null;
}
final List<T> choice = GuiChoose.getChoices(message, 0, 1, choices);
return choice.isEmpty() ? null : choice.get(0);
} // getChoiceOptional(String,T...)
public static <T> T oneOrNone(final String message, final Collection<T> choices) {
if ((choices == null) || choices.isEmpty()) {
return null;
}
final List<T> choice = GuiChoose.getChoices(message, 0, 1, choices);
return choice.isEmpty() ? null : choice.get(0);
} // getChoiceOptional(String,T...)
// returned Object will never be null
/**
* <p>
* getChoice.
* </p>
*
* @param <T>
* a T object.
* @param message
* a {@link java.lang.String} object.
* @param choices
* a T object.
* @return a T object.
*/
public static <T> T one(final String message, final T[] choices) {
final List<T> choice = GuiChoose.getChoices(message, 1, 1, choices);
assert choice.size() == 1;
return choice.get(0);
}
public static <T> T one(final String message, final Collection<T> choices) {
if (choices == null || choices.isEmpty())
return null;
if( choices.size() == 1)
return Iterables.getFirst(choices, null);
final List<T> choice = GuiChoose.getChoices(message, 1, 1, choices);
assert choice.size() == 1;
return choice.get(0);
}
public static <T> List<T> noneOrMany(final String message, final Collection<T> choices) {
return GuiChoose.getChoices(message, 0, choices.size(), choices, null, null);
}
// Nothing to choose here. Code uses this to just reveal one or more items
public static <T> void reveal(final String message, final T item) {
List<T> items = new ArrayList<T>();
items.add(item);
reveal(message, items);
}
public static <T> void reveal(final String message, final T[] items) {
GuiChoose.getChoices(message, -1, -1, items);
}
public static <T> void reveal(final String message, final Collection<T> items) {
GuiChoose.getChoices(message, -1, -1, items);
}
// Get Integer in range
public static Integer getInteger(final String message) {
return getInteger(message, 0, Integer.MAX_VALUE);
}
public static Integer getInteger(final String message, int min) {
return getInteger(message, min, Integer.MAX_VALUE);
}
public static Integer getInteger(final String message, int min, int max) {
if (max <= min) { return min; } //just return min if max <= min
//force cutting off after 100 numbers at most
if (max == Integer.MAX_VALUE) {
return getInteger(message, min, max, min + 99);
}
int count = max - min + 1;
if (count > 100) {
return getInteger(message, min, max, min + 99);
}
final Integer[] choices = new Integer[count];
for (int i = 0; i < count; i++) {
choices[i] = Integer.valueOf(i + min);
}
return GuiChoose.oneOrNone(message, choices);
}
public static Integer getInteger(final String message, int min, int max, int cutoff) {
if (max <= min || cutoff < min) { return min; } //just return min if max <= min or cutoff < min
if (cutoff >= max) { //fallback to regular integer prompt if cutoff at or after max
return getInteger(message, min, max);
}
List<Object> choices = new ArrayList<Object>();
for (int i = min; i <= cutoff; i++) {
choices.add(Integer.valueOf(i));
}
choices.add("Other...");
Object choice = GuiChoose.oneOrNone(message, choices);
if (choice instanceof Integer || choice == null) {
return (Integer)choice;
}
//if Other option picked, prompt for number input
String prompt = "Enter a number";
if (min != Integer.MIN_VALUE) {
if (max != Integer.MAX_VALUE) {
prompt += " between " + min + " and " + max;
}
else {
prompt += " greater than or equal to " + min;
}
}
else if (max != Integer.MAX_VALUE) {
prompt += " less than or equal to " + max;
}
prompt += ":";
while (true) {
String str = FOptionPane.showInputDialog(prompt, message);
if (str == null) { return null; } // that is 'cancel'
if (StringUtils.isNumeric(str)) {
Integer val = Integer.valueOf(str);
if (val >= min && val <= max) {
return val;
}
}
}
}
// returned Object will never be null
public static <T> List<T> getChoices(final String message, final int min, final int max, final T[] choices) {
return getChoices(message, min, max, Arrays.asList(choices), null, null);
}
public static <T> List<T> getChoices(final String message, final int min, final int max, final Collection<T> choices) {
return getChoices(message, min, max, choices, null, null);
}
public static <T> List<T> getChoices(final String message, final int min, final int max, final Collection<T> choices, final T selected, final Function<T, String> display) {
/*if (choices == null || choices.isEmpty()) {
if (min == 0) {
return new ArrayList<T>();
}
throw new RuntimeException("choice required from empty list");
}
Callable<List<T>> showChoice = new Callable<List<T>>() {
@Override
public List<T> call() {
ListChooser<T> c = new ListChooser<T>(message, min, max, choices, display);
final JList<T> list = c.getLstChoices();
list.addListSelectionListener(new ListSelectionListener() {
@Override
public void valueChanged(final ListSelectionEvent ev) {
if (list.getSelectedValue() instanceof Card) {
Card card = (Card) list.getSelectedValue();
if (card.isFaceDown() && FControl.mayShowCard(card)) {
CMatchUI.SINGLETON_INSTANCE.setCard(card, true);
}
else {
CMatchUI.SINGLETON_INSTANCE.setCard(card);
}
GuiUtils.clearPanelSelections();
GuiUtils.setPanelSelection(card);
}
if (list.getSelectedValue() instanceof InventoryItem) {
CMatchUI.SINGLETON_INSTANCE.setCard((InventoryItem) list.getSelectedValue());
}
}
});
if (selected != null) {
c.show(selected);
}
else {
c.show();
}
GuiUtils.clearPanelSelections();
return c.getSelectedValues();
}
};
FutureTask<List<T>> future = new FutureTask<List<T>>(showChoice);
FThreads.invokeInEdtAndWait(future);
try {
return future.get();
} catch (Exception e) { // should be no exception here
e.printStackTrace();
}*/
return null;
}
public static <T> List<T> many(final String title, final String topCaption, int cnt, final List<T> sourceChoices, Card referenceCard) {
return order(title, topCaption, cnt, cnt, sourceChoices, null, referenceCard, false);
}
public static <T> List<T> many(final String title, final String topCaption, int min, int max, final List<T> sourceChoices, Card referenceCard) {
int m2 = min >= 0 ? sourceChoices.size() - min : -1;
int m1 = max >= 0 ? sourceChoices.size() - max : -1;
return order(title, topCaption, m1, m2, sourceChoices, null, referenceCard, false);
}
public static <T> List<T> order(final String title, final String top, final List<T> sourceChoices, Card referenceCard) {
return order(title, top, 0, 0, sourceChoices, null, referenceCard, false);
}
public static <T extends Comparable<? super T>> List<T> sideboard(List<T> sideboard, List<T> deck) {
Collections.sort(deck);
Collections.sort(sideboard);
return order("Sideboard", "Main Deck", -1, -1, sideboard, deck, null, true);
}
private static <T> List<T> order(final String title, final String top, final int remainingObjectsMin, final int remainingObjectsMax,
final List<T> sourceChoices, final List<T> destChoices, final Card referenceCard, final boolean sideboardingMode) {
// An input box for handling the order of choices.
/*Callable<List<T>> callable = new Callable<List<T>>() {
@Override
public List<T> call() throws Exception {
DualListBox<T> dual = new DualListBox<T>(remainingObjectsMin, remainingObjectsMax, sourceChoices, destChoices);
dual.setSecondColumnLabelText(top);
dual.setSideboardMode(sideboardingMode);
dual.setTitle(title);
dual.pack();
dual.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
if (referenceCard != null) {
CMatchUI.SINGLETON_INSTANCE.setCard(referenceCard);
// MARKED FOR UPDATE
}
dual.setVisible(true);
List<T> objects = dual.getOrderedList();
dual.dispose();
GuiUtils.clearPanelSelections();
return objects;
}
};
FutureTask<List<T>> ft = new FutureTask<List<T>>(callable);
FThreads.invokeInEdtAndWait(ft);
try {
return ft.get();
} catch (Exception e) { // we have waited enough
e.printStackTrace();
}*/
return null;
}
// If comparer is NULL, T has to be comparable. Otherwise you'll get an exception from inside the Arrays.sort() routine
public static <T> T sortedOneOrNone(final String message, final T[] choices, Comparator<T> comparer) {
if ((choices == null) || (choices.length == 0)) {
return null;
}
final List<T> choice = GuiChoose.sortedGetChoices(message, 0, 1, choices, comparer);
return choice.isEmpty() ? null : choice.get(0);
} // getChoiceOptional(String,T...)
// If comparer is NULL, T has to be comparable. Otherwise you'll get an exception from inside the Arrays.sort() routine
public static <T> T sortedOneOrNone(final String message, final List<T> choices, Comparator<T> comparer) {
if ((choices == null) || choices.isEmpty()) {
return null;
}
final List<T> choice = GuiChoose.sortedGetChoices(message, 0, 1, choices, comparer);
return choice.isEmpty() ? null : choice.get(0);
} // getChoiceOptional(String,T...)
// If comparer is NULL, T has to be comparable. Otherwise you'll get an exception from inside the Arrays.sort() routine
public static <T> T sortedOne(final String message, final T[] choices, Comparator<T> comparer) {
final List<T> choice = GuiChoose.sortedGetChoices(message, 1, 1, choices, comparer);
assert choice.size() == 1;
return choice.get(0);
} // getChoice()
// If comparer is NULL, T has to be comparable. Otherwise you'll get an exception from inside the Arrays.sort() routine
public static <T> T sortedOne(final String message, final List<T> choices, Comparator<T> comparer) {
if ((choices == null) || (choices.size() == 0)) {
return null;
}
final List<T> choice = GuiChoose.sortedGetChoices(message, 1, 1, choices, comparer);
assert choice.size() == 1;
return choice.get(0);
}
// If comparer is NULL, T has to be comparable. Otherwise you'll get an exception from inside the Arrays.sort() routine
public static <T> List<T> sortedNoneOrMany(final String message, final List<T> choices, Comparator<T> comparer) {
return GuiChoose.sortedGetChoices(message, 0, choices.size(), choices, comparer);
}
// If comparer is NULL, T has to be comparable. Otherwise you'll get an exception from inside the Arrays.sort() routine
public static <T> List<T> sortedGetChoices(final String message, final int min, final int max, final T[] choices, Comparator<T> comparer) {
// You may create a copy of source array if callers expect the collection to be unchanged
Arrays.sort(choices, comparer);
return getChoices(message, min, max, choices);
}
// If comparer is NULL, T has to be comparable. Otherwise you'll get an exception from inside the Arrays.sort() routine
public static <T> List<T> sortedGetChoices(final String message, final int min, final int max, final List<T> choices, Comparator<T> comparer) {
// You may create a copy of source list if callers expect the collection to be unchanged
Collections.sort(choices, comparer);
return getChoices(message, min, max, choices);
}
}