mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-15 18:28:00 +00:00
* Better sideboarding: decks have no extra fields for changed parts, they are copied on sideboarding, new deck composition moved outside of GuiChoose.java
* Decks have no extra sections for variants (sideboard works in most cases) * Deck Format restrictions are in a separate class not related to GameType + DeckSection has its own toString overload + DualListBox operates CardPrinted properly (sideboarding dialog uses cardprinted instances) + ItemPool.remove method returns true if any elements were removed.
This commit is contained in:
1
.gitattributes
vendored
1
.gitattributes
vendored
@@ -13476,6 +13476,7 @@ src/main/java/forge/control/package-info.java -text
|
||||
src/main/java/forge/deck/CardCollections.java -text
|
||||
src/main/java/forge/deck/Deck.java svneol=native#text/plain
|
||||
src/main/java/forge/deck/DeckBase.java -text
|
||||
src/main/java/forge/deck/DeckFormat.java -text
|
||||
src/main/java/forge/deck/DeckGroup.java -text
|
||||
src/main/java/forge/deck/DeckRecognizer.java -text
|
||||
src/main/java/forge/deck/DeckSection.java -text
|
||||
|
||||
@@ -59,17 +59,9 @@ public class Deck extends DeckBase {
|
||||
*/
|
||||
private static final long serialVersionUID = -7478025567887481994L;
|
||||
|
||||
private transient boolean isEdited = false;
|
||||
private final DeckSection main;
|
||||
private final DeckSection sideboard;
|
||||
private final DeckSection planes;
|
||||
private final DeckSection schemes;
|
||||
|
||||
private transient DeckSection mainEdited;
|
||||
private transient DeckSection sideboardEdited;
|
||||
private final DeckSection sideboard; // commander, planes or schemes are also stored here
|
||||
private CardPrinted avatar;
|
||||
private CardPrinted commander;
|
||||
|
||||
|
||||
// gameType is from Constant.GameType, like GameType.Regular
|
||||
/**
|
||||
@@ -90,12 +82,7 @@ public class Deck extends DeckBase {
|
||||
super(name0);
|
||||
this.main = new DeckSection();
|
||||
this.sideboard = new DeckSection();
|
||||
this.mainEdited = new DeckSection();
|
||||
this.sideboardEdited = new DeckSection();
|
||||
this.avatar = null;
|
||||
this.commander = null;
|
||||
this.planes = new DeckSection();
|
||||
this.schemes = new DeckSection();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -116,26 +103,13 @@ public class Deck extends DeckBase {
|
||||
return this.getName();
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Getter for the field <code>main</code>.
|
||||
* </p>
|
||||
*
|
||||
* @return a {@link java.util.List} object.
|
||||
*/
|
||||
public DeckSection getMain() {
|
||||
return isEdited ? this.mainEdited : this.main;
|
||||
return this.main;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Getter for the field <code>sideboard</code>.
|
||||
* </p>
|
||||
*
|
||||
* @return a {@link java.util.List} object.
|
||||
*/
|
||||
// variants' extra deck sections used instead of sideboard (planes, commander, schemes) are here as well as usual sideboards
|
||||
public DeckSection getSideboard() {
|
||||
return isEdited ? this.sideboardEdited : this.sideboard;
|
||||
return this.sideboard;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -145,7 +119,7 @@ public class Deck extends DeckBase {
|
||||
*/
|
||||
@Override
|
||||
public ItemPoolView<CardPrinted> getCardPool() {
|
||||
return isEdited ? this.mainEdited : this.main;
|
||||
return this.main;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
@@ -158,13 +132,6 @@ public class Deck extends DeckBase {
|
||||
result.main.addAll(this.main);
|
||||
result.sideboard.addAll(this.sideboard);
|
||||
result.avatar = this.avatar;
|
||||
result.commander = this.commander;
|
||||
|
||||
//This if clause is really only necessary when cloning decks that were
|
||||
//around before schemes.
|
||||
if (this.schemes != null) {
|
||||
result.schemes.addAll(this.schemes);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -219,14 +186,14 @@ public class Deck extends DeckBase {
|
||||
|
||||
d.getMain().set(Deck.readCardList(sections.get("main")));
|
||||
d.getSideboard().set(Deck.readCardList(sections.get("sideboard")));
|
||||
List<String> cmd = Deck.readCardList(sections.get("commander"));
|
||||
String cmdName = cmd.isEmpty() ? null : cmd.get(0);
|
||||
d.commander = CardDb.instance().isCardSupported(cmdName) ? CardDb.instance().getCard(cmdName) : null;
|
||||
// try also earlier deck formats
|
||||
if ( d.getSideboard().isEmpty() ) { d.getSideboard().set(Deck.readCardList(sections.get("schemes"))); }
|
||||
if ( d.getSideboard().isEmpty() ) { d.getSideboard().set(Deck.readCardList(sections.get("planes"))); }
|
||||
if ( d.getSideboard().isEmpty() ) { d.getSideboard().set(Deck.readCardList(sections.get("commander"))); }
|
||||
|
||||
List<String> av = Deck.readCardList(sections.get("avatar"));
|
||||
String avName = av.isEmpty() ? null : av.get(0);
|
||||
d.avatar = CardDb.instance().isCardSupported(avName) ? CardDb.instance().getCard(avName) : null;
|
||||
d.getPlanes().set(Deck.readCardList(sections.get("planes")));
|
||||
d.getSchemes().set(Deck.readCardList(sections.get("schemes")));
|
||||
return d;
|
||||
}
|
||||
|
||||
@@ -303,20 +270,10 @@ public class Deck extends DeckBase {
|
||||
out.add(String.format("%s", "[sideboard]"));
|
||||
out.addAll(Deck.writeCardPool(this.getSideboard()));
|
||||
|
||||
if (getCommander() != null) {
|
||||
out.add(String.format("%s", "[commander]"));
|
||||
out.add(Deck.serializeSingleCard(getCommander(), 1));
|
||||
}
|
||||
if (getAvatar() != null) {
|
||||
out.add(String.format("%s", "[avatar]"));
|
||||
out.add(Deck.serializeSingleCard(getAvatar(), 1));
|
||||
}
|
||||
|
||||
out.add(String.format("%s", "[planes]"));
|
||||
out.addAll(Deck.writeCardPool(this.getPlanes()));
|
||||
|
||||
out.add(String.format("%s", "[schemes]"));
|
||||
out.addAll(Deck.writeCardPool(this.getSchemes()));
|
||||
return out;
|
||||
}
|
||||
|
||||
@@ -324,22 +281,9 @@ public class Deck extends DeckBase {
|
||||
* @return the commander
|
||||
*/
|
||||
public CardPrinted getCommander() {
|
||||
return commander;
|
||||
return sideboard != null && !sideboard.isEmpty() ? sideboard.get(0) : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the planes
|
||||
*/
|
||||
public DeckSection getPlanes() {
|
||||
return planes;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the schemes
|
||||
*/
|
||||
public DeckSection getSchemes() {
|
||||
return schemes;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the avatar
|
||||
@@ -354,40 +298,4 @@ public class Deck extends DeckBase {
|
||||
return arg1.getName();
|
||||
}
|
||||
};
|
||||
|
||||
public void clearDeckEdits() {
|
||||
isEdited = false;
|
||||
if (mainEdited != null) {
|
||||
mainEdited.clear();
|
||||
} else {
|
||||
mainEdited = new DeckSection();
|
||||
}
|
||||
if (sideboardEdited != null) {
|
||||
sideboardEdited.clear();
|
||||
} else {
|
||||
sideboardEdited = new DeckSection();
|
||||
}
|
||||
}
|
||||
|
||||
public void startDeckEdits() {
|
||||
isEdited = true;
|
||||
if (mainEdited.countAll() == 0) {
|
||||
mainEdited.add(main.toFlatList());
|
||||
}
|
||||
if (sideboardEdited.countAll() == 0) {
|
||||
sideboardEdited.add(sideboard.toFlatList());
|
||||
}
|
||||
}
|
||||
|
||||
public DeckSection getOriginalMain() {
|
||||
return this.main;
|
||||
}
|
||||
|
||||
public DeckSection getOriginalSideboard() {
|
||||
return this.sideboard;
|
||||
}
|
||||
|
||||
public boolean isEditedDeck() {
|
||||
return this.isEdited;
|
||||
}
|
||||
}
|
||||
|
||||
212
src/main/java/forge/deck/DeckFormat.java
Normal file
212
src/main/java/forge/deck/DeckFormat.java
Normal file
@@ -0,0 +1,212 @@
|
||||
/*
|
||||
* 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.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import org.apache.commons.lang.math.IntRange;
|
||||
|
||||
import forge.card.CardCoreType;
|
||||
import forge.item.CardDb;
|
||||
import forge.item.CardPrinted;
|
||||
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 ( new IntRange(60, Integer.MAX_VALUE), new IntRange(15), 4),
|
||||
Limited ( new IntRange(40, Integer.MAX_VALUE), null, Integer.MAX_VALUE),
|
||||
Commander ( new IntRange(99 /* commndr in SB*/), new IntRange(1), 1),
|
||||
Vanguard ( new IntRange(60, Integer.MAX_VALUE), new IntRange(0), 4),
|
||||
Planechase ( new IntRange(60, Integer.MAX_VALUE), new IntRange(0), 4),
|
||||
Archenemy ( new IntRange(60, Integer.MAX_VALUE), new IntRange(0), 4);
|
||||
|
||||
private final IntRange mainRange;
|
||||
private final IntRange sideRange; // null => no check
|
||||
private final int maxCardCopies;
|
||||
|
||||
|
||||
/**
|
||||
* Instantiates a new game type.
|
||||
*
|
||||
* @param isLimited
|
||||
* the is limited
|
||||
*/
|
||||
DeckFormat(IntRange main, IntRange 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 IntRange getSideRange() {
|
||||
return sideRange;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return the mainRange
|
||||
*/
|
||||
public IntRange getMainRange() {
|
||||
return mainRange;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return the maxCardCopies
|
||||
*/
|
||||
public int getMaxCardCopies() {
|
||||
return maxCardCopies;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@SuppressWarnings("incomplete-switch")
|
||||
public String getDeckConformanceProblem(Deck deck) {
|
||||
int deckSize = deck.getMain().countAll();
|
||||
|
||||
int min = getMainRange().getMinimumInteger();
|
||||
int max = getMainRange().getMaximumInteger();
|
||||
|
||||
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 no sideboard.
|
||||
|
||||
//TODO:Enforce color identity
|
||||
if (null == deck.getCommander()) {
|
||||
return "is missing a commander";
|
||||
}
|
||||
if (!deck.getCommander().getCard().getType().isLegendary()) {
|
||||
return "has a commander that is not a legendary creature";
|
||||
}
|
||||
|
||||
//No sideboarding in Commander
|
||||
if (!deck.getSideboard().isEmpty()) {
|
||||
return "has sideboard";
|
||||
}
|
||||
break;
|
||||
|
||||
case Planechase: //Must contain at least 10 planes/phenomenons, but max 2 phenomenons. Singleton.
|
||||
if (deck.getSideboard().countAll() < 10) {
|
||||
return "should gave at least 10 planes";
|
||||
}
|
||||
int phenoms = 0;
|
||||
for (Entry<CardPrinted, Integer> cp : deck.getSideboard()) {
|
||||
|
||||
if (cp.getKey().getCard().getType().typeContains(CardCoreType.Phenomenon)) {
|
||||
phenoms++;
|
||||
}
|
||||
if (cp.getValue() > 1) {
|
||||
return "must not contain multiple copies of any 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.
|
||||
if (deck.getSideboard().countAll() < 20) {
|
||||
return "must contain at least 20 schemes";
|
||||
}
|
||||
|
||||
for (Entry<CardPrinted, Integer> cp : deck.getSideboard()) {
|
||||
if (cp.getValue() > 2) {
|
||||
return "must not contain more than 2 copies of any Scheme";
|
||||
}
|
||||
}
|
||||
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 and Relentless Rats
|
||||
|
||||
DeckSection tmp = new DeckSection(deck.getMain());
|
||||
tmp.addAll(deck.getSideboard());
|
||||
if (null != deck.getCommander() && this == Commander) {
|
||||
tmp.add(deck.getCommander());
|
||||
}
|
||||
|
||||
List<String> limitExceptions = Arrays.asList("Relentless Rats");
|
||||
|
||||
// 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, CardPrinted.FN_GET_NAME)) {
|
||||
|
||||
CardPrinted simpleCard = CardDb.instance().getCard(cp.getKey());
|
||||
boolean canHaveMultiple = simpleCard.getCard().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.getSideboard().countAll();
|
||||
IntRange sbRange = getSideRange();
|
||||
if (sbRange != null && sideboardSize > 0 && !sbRange.containsInteger(sideboardSize)) {
|
||||
return sbRange.getMinimumInteger() == sbRange.getMaximumInteger()
|
||||
? String.format("must have a sideboard of %d cards or no sideboard at all", sbRange.getMaximumInteger())
|
||||
: String.format("must have a sideboard of %d to %d cards or no sideboard at all", sbRange.getMinimumInteger(), sbRange.getMaximumInteger());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -128,4 +128,33 @@ public class DeckSection extends ItemPool<CardPrinted> {
|
||||
this.add(CardDb.instance().getCard(cardName));
|
||||
}
|
||||
|
||||
/**
|
||||
* returns n-th card from this DeckSection. LINEAR time.
|
||||
* @param i
|
||||
* @return
|
||||
*/
|
||||
public CardPrinted get(int n) {
|
||||
for(Entry<CardPrinted, Integer> e : this)
|
||||
{
|
||||
n -= e.getValue();
|
||||
if ( n <= 0 ) return e.getKey();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
if (this.isEmpty()) return "[]";
|
||||
|
||||
boolean isFirst = true;
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append('[');
|
||||
for (Entry<CardPrinted, Integer> e : this) {
|
||||
if ( isFirst ) isFirst = false;
|
||||
else sb.append(", ");
|
||||
|
||||
sb.append(e.getValue()).append(" x ").append(e.getKey().getName());
|
||||
}
|
||||
return sb.append(']').toString();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -320,9 +320,9 @@ public class DeckgenUtil {
|
||||
int attemptsLeft = 100; // to avoid endless loop
|
||||
while (schemesToAdd > 0 && attemptsLeft > 0) {
|
||||
CardPrinted cp = Aggregates.random(allSchemes);
|
||||
int appearances = res.getSchemes().count(cp) + 1;
|
||||
int appearances = res.getSideboard().count(cp) + 1;
|
||||
if (appearances < 2) {
|
||||
res.getSchemes().add(cp);
|
||||
res.getSideboard().add(cp);
|
||||
schemesToAdd--;
|
||||
} else {
|
||||
attemptsLeft--;
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
*/
|
||||
package forge.deck.io;
|
||||
|
||||
import forge.game.GameType;
|
||||
import forge.deck.DeckFormat;
|
||||
import forge.game.player.PlayerType;
|
||||
import forge.util.FileSection;
|
||||
|
||||
@@ -39,7 +39,7 @@ public class DeckFileHeader {
|
||||
private static final String CSTM_POOL = "Custom Pool";
|
||||
private static final String PLAYER_TYPE = "PlayerType";
|
||||
|
||||
private final GameType deckType;
|
||||
private final DeckFormat deckType;
|
||||
private final PlayerType playerType;
|
||||
private final boolean customPool;
|
||||
|
||||
@@ -55,11 +55,10 @@ public class DeckFileHeader {
|
||||
public DeckFileHeader(final FileSection kvPairs) {
|
||||
this.name = kvPairs.get(DeckFileHeader.NAME);
|
||||
this.comment = kvPairs.get(DeckFileHeader.COMMENT);
|
||||
this.deckType = GameType.smartValueOf(kvPairs.get(DeckFileHeader.DECK_TYPE), GameType.Constructed);
|
||||
this.deckType = DeckFormat.smartValueOf(kvPairs.get(DeckFileHeader.DECK_TYPE), DeckFormat.Constructed);
|
||||
this.customPool = kvPairs.getBoolean(DeckFileHeader.CSTM_POOL);
|
||||
this.playerType = "computer".equalsIgnoreCase(kvPairs.get(DeckFileHeader.PLAYER))
|
||||
|| "ai".equalsIgnoreCase(kvPairs.get(DeckFileHeader.PLAYER_TYPE)) ? PlayerType.COMPUTER
|
||||
: PlayerType.HUMAN;
|
||||
boolean isForAi = "computer".equalsIgnoreCase(kvPairs.get(DeckFileHeader.PLAYER)) || "ai".equalsIgnoreCase(kvPairs.get(DeckFileHeader.PLAYER_TYPE));
|
||||
this.playerType = isForAi ? PlayerType.COMPUTER : PlayerType.HUMAN;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -103,7 +102,7 @@ public class DeckFileHeader {
|
||||
*
|
||||
* @return the deck type
|
||||
*/
|
||||
public final GameType getDeckType() {
|
||||
public final DeckFormat getDeckType() {
|
||||
return this.deckType;
|
||||
}
|
||||
|
||||
|
||||
@@ -214,7 +214,7 @@ public class OldDeckParser {
|
||||
}
|
||||
break;
|
||||
|
||||
case Sealed:
|
||||
case Limited:
|
||||
final boolean isAi = dh.getPlayerType() == PlayerType.COMPUTER;
|
||||
name = name.startsWith("AI_") ? name.replace("AI_", "") : name;
|
||||
|
||||
|
||||
@@ -138,12 +138,6 @@ public class GameNew {
|
||||
final Random generator = MyRandom.getRandom();
|
||||
boolean useAnte = Singletons.getModel().getPreferences().getPrefBoolean(FPref.UI_ANTE);
|
||||
|
||||
if (!Singletons.getModel().getMatch().getPlayedGames().isEmpty()) {
|
||||
deck.startDeckEdits();
|
||||
sideboard(player, deck, canRandomFoil, generator, useAnte);
|
||||
} else {
|
||||
deck.clearDeckEdits();
|
||||
}
|
||||
prepareGameLibrary(player, deck, removedAnteCards, rAICards, canRandomFoil, generator, useAnte);
|
||||
|
||||
// Shuffling
|
||||
@@ -157,42 +151,54 @@ public class GameNew {
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean sideboard(final Player player, final Deck deck, boolean canRandomFoil, Random generator, boolean useAnte) {
|
||||
private static Deck sideboard(final Player player, final Deck deck) {
|
||||
final GameType gameType = Singletons.getModel().getMatch().getGameType();
|
||||
boolean hasSideboard = (deck.getSideboard().countAll() > 0);
|
||||
boolean deckHasSideboard = (deck.getSideboard().countAll() > 0);
|
||||
|
||||
DeckSection sideboard = deck.getSideboard();
|
||||
int sideboardSize = (gameType == GameType.Draft || gameType == GameType.Sealed) ? -1 : sideboard.countAll();
|
||||
|
||||
if (!hasSideboard) {
|
||||
return false;
|
||||
|
||||
if (!deckHasSideboard || !gameType.isSideboardingAllowed()) {
|
||||
return deck;
|
||||
}
|
||||
|
||||
if (player.isComputer()) {
|
||||
if (player.isComputer())
|
||||
// Here is where the AI could sideboard, but needs to gather hints during the first game about what to SB
|
||||
return deck;
|
||||
|
||||
return false;
|
||||
} else {
|
||||
// Human Sideboarding
|
||||
boolean validDeck = false;
|
||||
int deckMinSize = Math.min(deck.getMain().countAll(), gameType.getMainRange().getMinimumInteger());
|
||||
// Human Sideboarding
|
||||
|
||||
while (!validDeck) {
|
||||
GuiChoose.getOrderChoices("Sideboard", "Main Deck", sideboardSize,
|
||||
deck.getSideboard().toForgeCardList(), deck.getMain().toForgeCardList(), null, true, deck);
|
||||
int deckMinSize = Math.min(deck.getMain().countAll(), gameType.getDecksFormat().getMainRange().getMinimumInteger());
|
||||
//IntRange sbRange = gameType.getDecksFormat().getSideRange();
|
||||
int sideboardSize = sideboard.countAll();
|
||||
|
||||
if (deck.getMain().countAll() >= deckMinSize) {
|
||||
validDeck = true;
|
||||
} else {
|
||||
StringBuilder errMsg = new StringBuilder("Too few cards in your main deck (minimum ");
|
||||
errMsg.append(deckMinSize);
|
||||
errMsg.append("), please make modifications to your deck again.");
|
||||
JOptionPane.showMessageDialog(null, errMsg.toString(), "Invalid deck", JOptionPane.ERROR_MESSAGE);
|
||||
}
|
||||
DeckSection newSb = new DeckSection();
|
||||
List<CardPrinted> newMain = null;
|
||||
|
||||
|
||||
while (newMain == null || newMain.size() < deckMinSize) {
|
||||
|
||||
if ( newMain != null ) {
|
||||
String errMsg = String.format("Too few cards in your main deck (minimum %d), please make modifications to your deck again.", deckMinSize);
|
||||
JOptionPane.showMessageDialog(null, errMsg, "Invalid deck", JOptionPane.ERROR_MESSAGE);
|
||||
}
|
||||
|
||||
|
||||
newMain = GuiChoose.getOrderChoices("Sideboard", "Main Deck", sideboardSize, deck.getSideboard().toFlatList(), deck.getMain().toFlatList(), null, true);
|
||||
}
|
||||
return true;
|
||||
|
||||
newSb.clear();
|
||||
newSb.addAll(deck.getMain());
|
||||
newSb.addAll(deck.getSideboard());
|
||||
for(CardPrinted c : newMain)
|
||||
newSb.remove(c);
|
||||
|
||||
Deck res = (Deck) deck.copyTo(deck.getName());
|
||||
res.getMain().clear();
|
||||
res.getMain().add(newMain);
|
||||
res.getSideboard().clear();
|
||||
res.getSideboard().addAll(newSb);
|
||||
return res;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -252,7 +258,16 @@ public class GameNew {
|
||||
}
|
||||
|
||||
|
||||
prepareSingleLibrary(player, p.getValue().getDeck(), removedAnteCards, rAICards, canRandomFoil);
|
||||
Deck toUse;
|
||||
boolean isFirstGame = Singletons.getModel().getMatch().getPlayedGames().isEmpty();
|
||||
if (!isFirstGame) {
|
||||
toUse = sideboard(player, p.getValue().getCurrentDeck());
|
||||
} else {
|
||||
p.getValue().restoreOriginalDeck();
|
||||
toUse = p.getValue().getCurrentDeck();
|
||||
}
|
||||
|
||||
prepareSingleLibrary(player, toUse, removedAnteCards, rAICards, canRandomFoil);
|
||||
player.updateObservers();
|
||||
bf.updateObservers();
|
||||
player.getZone(ZoneType.Hand).updateObservers();
|
||||
|
||||
@@ -1,229 +1,51 @@
|
||||
/*
|
||||
* 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.game;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map.Entry;
|
||||
import forge.deck.DeckFormat;
|
||||
|
||||
import org.apache.commons.lang.math.IntRange;
|
||||
|
||||
import forge.card.CardCoreType;
|
||||
import forge.deck.Deck;
|
||||
import forge.deck.DeckSection;
|
||||
import forge.item.CardDb;
|
||||
import forge.item.CardPrinted;
|
||||
import forge.util.Aggregates;
|
||||
|
||||
/**
|
||||
* GameType is an enum to determine the type of current game. :)
|
||||
/**
|
||||
* TODO: Write javadoc for this type.
|
||||
*
|
||||
*/
|
||||
public enum GameType {
|
||||
|
||||
// Limited Main board: allowed size SB: allowed size Max distinct non basic cards
|
||||
Constructed ( false, new IntRange(60, Integer.MAX_VALUE), new IntRange(15), 4),
|
||||
Sealed ( true, new IntRange(40, Integer.MAX_VALUE), null, Integer.MAX_VALUE),
|
||||
Draft ( true, new IntRange(40, Integer.MAX_VALUE), null, Integer.MAX_VALUE),
|
||||
Commander ( false, new IntRange(99 /* +cmndr aside */), new IntRange(0), 1),
|
||||
Quest ( true, new IntRange(40, Integer.MAX_VALUE), new IntRange(15), 4),
|
||||
Vanguard ( false, new IntRange(60, Integer.MAX_VALUE), new IntRange(0), 4),
|
||||
Planechase ( false, new IntRange(60, Integer.MAX_VALUE), new IntRange(0), 4),
|
||||
Archenemy ( false, new IntRange(60, Integer.MAX_VALUE), new IntRange(0), 4),
|
||||
Gauntlet ( true, new IntRange(40, Integer.MAX_VALUE), null, Integer.MAX_VALUE);
|
||||
// deck composition rules, isPoolRestricted, can sideboard between matches
|
||||
Sealed ( DeckFormat.Limited, true, true ),
|
||||
Draft ( DeckFormat.Limited, true, true ),
|
||||
Gauntlet ( DeckFormat.Limited, true, true ),
|
||||
Quest ( DeckFormat.Constructed, true, true ),
|
||||
Constructed ( DeckFormat.Constructed, false, true ),
|
||||
Archenemy ( DeckFormat.Archenemy, false, false ),
|
||||
Planechase ( DeckFormat.Planechase, false, false ),
|
||||
Vanguard ( DeckFormat.Vanguard, true, true );
|
||||
|
||||
private final boolean bLimited;
|
||||
private final IntRange mainRange;
|
||||
private final IntRange sideRange; // null => no check
|
||||
private final int maxCardCopies;
|
||||
|
||||
|
||||
/**
|
||||
* Checks if is limited.
|
||||
*
|
||||
* @return true, if is limited
|
||||
*/
|
||||
public final boolean isLimited() {
|
||||
return this.bLimited;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Instantiates a new game type.
|
||||
*
|
||||
* @param isLimited
|
||||
* the is limited
|
||||
*/
|
||||
GameType(final boolean isLimited, IntRange main, IntRange side, int maxCopies) {
|
||||
this.bLimited = isLimited;
|
||||
mainRange = main;
|
||||
sideRange = side;
|
||||
maxCardCopies = maxCopies;
|
||||
private final DeckFormat decksFormat;
|
||||
private final boolean bCardpoolLimited;
|
||||
private final boolean canSideboard;
|
||||
|
||||
GameType(DeckFormat formatType, boolean isDeckBuilderLimited, boolean sideboardingAllowed ) {
|
||||
bCardpoolLimited = isDeckBuilderLimited;
|
||||
decksFormat = formatType;
|
||||
canSideboard = sideboardingAllowed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Smart value of.
|
||||
*
|
||||
* @param value the value
|
||||
* @param defaultValue the default value
|
||||
* @return the game type
|
||||
* @return the decksFormat
|
||||
*/
|
||||
public static GameType smartValueOf(final String value, GameType defaultValue) {
|
||||
if (null == value) {
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
final String valToCompate = value.trim();
|
||||
for (final GameType v : GameType.values()) {
|
||||
if (v.name().compareToIgnoreCase(valToCompate) == 0) {
|
||||
return v;
|
||||
}
|
||||
}
|
||||
|
||||
throw new IllegalArgumentException("No element named " + value + " in enum GameType");
|
||||
public DeckFormat getDecksFormat() {
|
||||
return decksFormat;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return the sideRange
|
||||
* @return the isCardpoolLimited
|
||||
*/
|
||||
public IntRange getSideRange() {
|
||||
return sideRange;
|
||||
public boolean isCardpoolLimited() {
|
||||
return bCardpoolLimited;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return the mainRange
|
||||
* @return the canSideboard
|
||||
*/
|
||||
public IntRange getMainRange() {
|
||||
return mainRange;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return the maxCardCopies
|
||||
*/
|
||||
public int getMaxCardCopies() {
|
||||
return maxCardCopies;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@SuppressWarnings("incomplete-switch")
|
||||
public String getDeckConformanceProblem(Deck deck) {
|
||||
int deckSize = deck.getMain().countAll();
|
||||
|
||||
int min = getMainRange().getMinimumInteger();
|
||||
int max = getMainRange().getMaximumInteger();
|
||||
|
||||
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 no sideboard.
|
||||
|
||||
//TODO:Enforce color identity
|
||||
if (null == deck.getCommander()) {
|
||||
return "is missing a commander";
|
||||
}
|
||||
if (!deck.getCommander().getCard().getType().isLegendary()) {
|
||||
return "has a commander that is not a legendary creature";
|
||||
}
|
||||
|
||||
//No sideboarding in Commander
|
||||
if (!deck.getSideboard().isEmpty()) {
|
||||
return "has sideboard";
|
||||
}
|
||||
break;
|
||||
|
||||
case Planechase: //Must contain at least 10 planes/phenomenons, but max 2 phenomenons. Singleton.
|
||||
if (deck.getPlanes().countAll() < 10) {
|
||||
return "should gave at least 10 planes";
|
||||
}
|
||||
int phenoms = 0;
|
||||
for (Entry<CardPrinted, Integer> cp : deck.getPlanes()) {
|
||||
|
||||
if (cp.getKey().getCard().getType().typeContains(CardCoreType.Phenomenon)) {
|
||||
phenoms++;
|
||||
}
|
||||
if (cp.getValue() > 1) {
|
||||
return "must not contain multiple copies of any 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.
|
||||
if (deck.getSchemes().countAll() < 20) {
|
||||
return "must contain at least 20 schemes";
|
||||
}
|
||||
|
||||
for (Entry<CardPrinted, Integer> cp : deck.getSchemes()) {
|
||||
if (cp.getValue() > 2) {
|
||||
return "must not contain more than 2 copies of any Scheme";
|
||||
}
|
||||
}
|
||||
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 and Relentless Rats
|
||||
|
||||
DeckSection tmp = new DeckSection(deck.getMain());
|
||||
tmp.addAll(deck.getSideboard());
|
||||
if (null != deck.getCommander()) {
|
||||
tmp.add(deck.getCommander());
|
||||
}
|
||||
|
||||
List<String> limitExceptions = Arrays.asList("Relentless Rats");
|
||||
|
||||
// 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, CardPrinted.FN_GET_NAME)) {
|
||||
|
||||
CardPrinted simpleCard = CardDb.instance().getCard(cp.getKey());
|
||||
boolean canHaveMultiple = simpleCard.getCard().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.getSideboard().countAll();
|
||||
IntRange sbRange = getSideRange();
|
||||
if (sbRange != null && sideboardSize > 0 && !sbRange.containsInteger(sideboardSize)) {
|
||||
return sbRange.getMinimumInteger() == sbRange.getMaximumInteger()
|
||||
? String.format("must have a sideboard of %d cards or no sideboard at all", sbRange.getMaximumInteger())
|
||||
: String.format("must have a sideboard of %d to %d cards or no sideboard at all", sbRange.getMinimumInteger(), sbRange.getMaximumInteger());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return null;
|
||||
public boolean isSideboardingAllowed() {
|
||||
return canSideboard;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -257,9 +257,15 @@ public class MatchController {
|
||||
*/
|
||||
public Deck getPlayersDeck(LobbyPlayer lobbyPlayer) {
|
||||
PlayerStartConditions cond = players.get(lobbyPlayer);
|
||||
return cond == null ? null : cond.getDeck();
|
||||
return cond == null ? null : cond.getCurrentDeck();
|
||||
}
|
||||
|
||||
public Deck getPlayersOriginalDeck(LobbyPlayer lobbyPlayer) {
|
||||
PlayerStartConditions cond = players.get(lobbyPlayer);
|
||||
return cond == null ? null : cond.getOriginalDeck();
|
||||
}
|
||||
|
||||
|
||||
public Map<LobbyPlayer, PlayerStartConditions> getPlayers() {
|
||||
return players;
|
||||
}
|
||||
|
||||
@@ -7,7 +7,9 @@ import forge.deck.Deck;
|
||||
|
||||
|
||||
public class PlayerStartConditions {
|
||||
private final Deck deck;
|
||||
private final Deck originalDeck;
|
||||
private Deck currentDeck;
|
||||
|
||||
private int startingLife = 20;
|
||||
private int startingHand = 7;
|
||||
private Supplier<Iterable<Card>> cardsOnBattlefield = null;
|
||||
@@ -15,12 +17,18 @@ public class PlayerStartConditions {
|
||||
private Supplier<Iterable<Card>> schemes = null;
|
||||
|
||||
public PlayerStartConditions(Deck deck0) {
|
||||
deck = deck0;
|
||||
originalDeck = deck0;
|
||||
currentDeck = originalDeck;
|
||||
}
|
||||
|
||||
public final Deck getDeck() {
|
||||
return deck;
|
||||
public final Deck getOriginalDeck() {
|
||||
return originalDeck;
|
||||
}
|
||||
|
||||
public final Deck getCurrentDeck() {
|
||||
return currentDeck;
|
||||
}
|
||||
|
||||
public final int getStartingLife() {
|
||||
return startingLife;
|
||||
}
|
||||
@@ -78,5 +86,12 @@ public class PlayerStartConditions {
|
||||
this.schemes = s;
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO: Write javadoc for this method.
|
||||
*/
|
||||
public void restoreOriginalDeck() {
|
||||
currentDeck = originalDeck;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -24,8 +24,8 @@ import forge.Card;
|
||||
import forge.Singletons;
|
||||
import forge.card.spellability.SpellAbility;
|
||||
import forge.control.input.Input;
|
||||
import forge.game.GameState;
|
||||
import forge.game.GameType;
|
||||
import forge.game.GameState;
|
||||
import forge.game.zone.ZoneType;
|
||||
import forge.gui.GuiChoose;
|
||||
import forge.gui.match.CMatchUI;
|
||||
|
||||
@@ -23,6 +23,7 @@ import forge.gui.toolbox.FList;
|
||||
import forge.gui.toolbox.FPanel;
|
||||
import forge.gui.toolbox.FScrollPane;
|
||||
import forge.gui.toolbox.FSkin;
|
||||
import forge.item.CardPrinted;
|
||||
|
||||
// An input box for handling the order of choices.
|
||||
// Left box has the original choices
|
||||
@@ -168,6 +169,8 @@ public class DualListBox<T> extends FPanel {
|
||||
card = (Card) obj;
|
||||
} else if (obj instanceof SpellAbility) {
|
||||
card = ((SpellAbility) obj).getSourceCard();
|
||||
} else if (obj instanceof CardPrinted) {
|
||||
card = ((CardPrinted) obj).toForgeCard();
|
||||
}
|
||||
|
||||
GuiUtils.clearPanelSelections();
|
||||
|
||||
@@ -13,7 +13,6 @@ import javax.swing.event.ListSelectionEvent;
|
||||
import javax.swing.event.ListSelectionListener;
|
||||
|
||||
import forge.Card;
|
||||
import forge.deck.Deck;
|
||||
import forge.gui.match.CMatchUI;
|
||||
import forge.item.InventoryItem;
|
||||
|
||||
@@ -205,11 +204,11 @@ public class GuiChoose {
|
||||
|
||||
public static <T> List<T> getOrderChoices(final String title, final String top, int remainingObjects,
|
||||
final List<T> sourceChoices, List<T> destChoices, Card referenceCard) {
|
||||
return getOrderChoices(title, top, remainingObjects, sourceChoices, destChoices, referenceCard, false, null);
|
||||
return getOrderChoices(title, top, remainingObjects, sourceChoices, destChoices, referenceCard, false);
|
||||
}
|
||||
|
||||
public static <T> List<T> getOrderChoices(final String title, final String top, int remainingObjects,
|
||||
final List<T> sourceChoices, List<T> destChoices, Card referenceCard, boolean sideboardingMode, Deck persistentDeck) {
|
||||
final List<T> sourceChoices, List<T> destChoices, Card referenceCard, boolean sideboardingMode) {
|
||||
// An input box for handling the order of choices.
|
||||
final JFrame frame = new JFrame();
|
||||
DualListBox<T> dual = new DualListBox<T>(remainingObjects, top, sourceChoices, destChoices, referenceCard, sideboardingMode);
|
||||
@@ -235,13 +234,6 @@ public class GuiChoose {
|
||||
|
||||
List<T> objects = dual.getOrderedList();
|
||||
|
||||
if (sideboardingMode) {
|
||||
persistentDeck.getMain().clear();
|
||||
persistentDeck.getMain().add((List<Card>) dual.getOrderedList());
|
||||
persistentDeck.getSideboard().clear();
|
||||
persistentDeck.getSideboard().add((List<Card>) dual.getRemainingSourceList());
|
||||
}
|
||||
|
||||
dialog.dispose();
|
||||
GuiUtils.clearPanelSelections();
|
||||
return objects;
|
||||
|
||||
@@ -126,7 +126,7 @@ public final class CEditorScheme extends ACEditorBase<CardPrinted, Deck> {
|
||||
schemes.add(cp);
|
||||
}
|
||||
this.getTableCatalog().setDeck(ItemPool.createFrom(schemes, CardPrinted.class));
|
||||
this.getTableDeck().setDeck(this.controller.getModel().getSchemes());
|
||||
this.getTableDeck().setDeck(this.controller.getModel().getSideboard());
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -337,7 +337,7 @@ public class SSubmenuQuestUtil {
|
||||
System.out.println(msg);
|
||||
return;
|
||||
}
|
||||
String errorMessage = GameType.Quest.getDeckConformanceProblem(deck);
|
||||
String errorMessage = GameType.Quest.getDecksFormat().getDeckConformanceProblem(deck);
|
||||
if (null != errorMessage) {
|
||||
JOptionPane.showMessageDialog(null, "Your deck " + errorMessage + " Please edit or choose a different deck.", "Invalid deck", JOptionPane.ERROR_MESSAGE);
|
||||
return;
|
||||
|
||||
@@ -11,6 +11,7 @@ import forge.Command;
|
||||
import forge.Singletons;
|
||||
import forge.control.Lobby;
|
||||
import forge.deck.Deck;
|
||||
import forge.deck.DeckFormat;
|
||||
import forge.game.GameType;
|
||||
import forge.game.MatchController;
|
||||
import forge.game.MatchStartHelper;
|
||||
@@ -98,7 +99,7 @@ public enum CSubmenuConstructed implements ICDoc {
|
||||
Deck humanDeck = VSubmenuConstructed.SINGLETON_INSTANCE.getDcHuman().getDeck();
|
||||
|
||||
if (Singletons.getModel().getPreferences().getPrefBoolean(FPref.ENFORCE_DECK_LEGALITY)) {
|
||||
String errorMessage = GameType.Constructed.getDeckConformanceProblem(humanDeck);
|
||||
String errorMessage = DeckFormat.Constructed.getDeckConformanceProblem(humanDeck);
|
||||
if (null != errorMessage) {
|
||||
JOptionPane.showMessageDialog(null, "Your deck " + errorMessage, "Invalid deck", JOptionPane.ERROR_MESSAGE);
|
||||
return;
|
||||
|
||||
@@ -14,6 +14,7 @@ import forge.Singletons;
|
||||
import forge.control.FControl;
|
||||
import forge.control.Lobby;
|
||||
import forge.deck.Deck;
|
||||
import forge.deck.DeckFormat;
|
||||
import forge.deck.DeckGroup;
|
||||
import forge.game.GameType;
|
||||
import forge.game.MatchController;
|
||||
@@ -100,7 +101,7 @@ public enum CSubmenuDraft implements ICDoc {
|
||||
"No deck selected for human!\r\n(You may need to build a new deck.)",
|
||||
"No deck", JOptionPane.ERROR_MESSAGE);
|
||||
return;
|
||||
} else if (null != GameType.Draft.getDeckConformanceProblem(humanDeck)) {
|
||||
} else if (null != DeckFormat.Limited.getDeckConformanceProblem(humanDeck)) {
|
||||
JOptionPane.showMessageDialog(null,
|
||||
"The selected deck doesn't have enough cards to play (minimum 40)."
|
||||
+ "\r\nUse the deck editor to choose the cards you want before starting.",
|
||||
|
||||
@@ -19,6 +19,7 @@ import forge.Singletons;
|
||||
import forge.control.FControl;
|
||||
import forge.deck.Deck;
|
||||
import forge.deck.DeckBase;
|
||||
import forge.deck.DeckFormat;
|
||||
import forge.deck.DeckGroup;
|
||||
import forge.game.limited.ReadDraftRankings;
|
||||
import forge.game.GameType;
|
||||
@@ -112,7 +113,7 @@ public enum CSubmenuSealed implements ICDoc {
|
||||
"Please build and/or select a deck for yourself.",
|
||||
"No deck", JOptionPane.ERROR_MESSAGE);
|
||||
return;
|
||||
} else if (null != GameType.Sealed.getDeckConformanceProblem(human)) {
|
||||
} else if (null != DeckFormat.Limited.getDeckConformanceProblem(human)) {
|
||||
JOptionPane.showMessageDialog(null,
|
||||
"The selected deck doesn't have enough cards to play (minimum 40)."
|
||||
+ "\r\nUse the deck editor to choose the cards you want before starting.",
|
||||
@@ -125,7 +126,6 @@ public enum CSubmenuSealed implements ICDoc {
|
||||
Singletons.getModel().getGauntletMini().launch(matches, human, GameType.Sealed);
|
||||
}
|
||||
|
||||
/** */
|
||||
@SuppressWarnings("unchecked")
|
||||
private <T extends DeckBase> void setupSealed() {
|
||||
|
||||
|
||||
@@ -4,13 +4,9 @@ import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
|
||||
import javax.swing.SwingUtilities;
|
||||
import javax.swing.SwingWorker;
|
||||
|
||||
import com.google.common.collect.Iterables;
|
||||
|
||||
import forge.Command;
|
||||
import forge.GameActionUtil;
|
||||
import forge.Singletons;
|
||||
@@ -31,6 +27,7 @@ import forge.gui.toolbox.FDeckChooser;
|
||||
import forge.item.CardPrinted;
|
||||
import forge.properties.ForgePreferences;
|
||||
import forge.properties.ForgePreferences.FPref;
|
||||
import forge.util.Aggregates;
|
||||
|
||||
/**
|
||||
* Controls the constructed submenu in the home UI.
|
||||
@@ -42,7 +39,7 @@ public enum CSubmenuArchenemy implements ICDoc {
|
||||
/** */
|
||||
SINGLETON_INSTANCE;
|
||||
private final VSubmenuArchenemy view = VSubmenuArchenemy.SINGLETON_INSTANCE;
|
||||
|
||||
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see forge.gui.home.ICSubmenu#initialize()
|
||||
@@ -127,8 +124,6 @@ public enum CSubmenuArchenemy implements ICDoc {
|
||||
final SwingWorker<Object, Void> worker = new SwingWorker<Object, Void>() {
|
||||
@Override
|
||||
public Object doInBackground() {
|
||||
Random rnd = new Random();
|
||||
String nl = System.getProperty("line.separator");
|
||||
boolean usedDefaults = false;
|
||||
|
||||
List<Deck> playerDecks = new ArrayList<Deck>();
|
||||
@@ -147,12 +142,12 @@ public enum CSubmenuArchenemy implements ICDoc {
|
||||
Object obj = view.getArchenemySchemes().getSelectedValue();
|
||||
|
||||
boolean useDefault = VSubmenuArchenemy.SINGLETON_INSTANCE.getCbUseDefaultSchemes().isSelected();
|
||||
useDefault &= !playerDecks.get(0).getSchemes().isEmpty();
|
||||
useDefault &= !playerDecks.get(0).getSideboard().isEmpty();
|
||||
|
||||
System.out.println(useDefault);
|
||||
if (useDefault) {
|
||||
|
||||
schemes = playerDecks.get(0).getSchemes().toFlatList();
|
||||
schemes = playerDecks.get(0).getSideboard().toFlatList();
|
||||
System.out.println(schemes.toString());
|
||||
usedDefaults = true;
|
||||
|
||||
@@ -162,14 +157,14 @@ public enum CSubmenuArchenemy implements ICDoc {
|
||||
String sel = (String) obj;
|
||||
if (sel.equals("Random")) {
|
||||
|
||||
schemes = Iterables.get(view.getAllSchemeDecks(), rnd.nextInt(Iterables.size(view.getAllSchemeDecks()))).getSchemes().toFlatList();
|
||||
schemes = Aggregates.random(view.getAllSchemeDecks()).getSideboard().toFlatList();
|
||||
} else {
|
||||
|
||||
//Generate
|
||||
schemes = DeckgenUtil.generateSchemeDeck().getSchemes().toFlatList();
|
||||
schemes = DeckgenUtil.generateSchemeDeck().getSideboard().toFlatList();
|
||||
}
|
||||
} else {
|
||||
schemes = ((Deck) obj).getSchemes().toFlatList();
|
||||
schemes = ((Deck) obj).getSideboard().toFlatList();
|
||||
}
|
||||
}
|
||||
if (schemes == null) {
|
||||
|
||||
@@ -11,8 +11,8 @@ import forge.Card;
|
||||
import forge.Singletons;
|
||||
import forge.control.FControl;
|
||||
import forge.deck.Deck;
|
||||
import forge.game.GameOutcome;
|
||||
import forge.game.GameType;
|
||||
import forge.game.GameOutcome;
|
||||
import forge.game.MatchController;
|
||||
import forge.game.player.Player;
|
||||
import forge.game.zone.ZoneType;
|
||||
@@ -133,10 +133,13 @@ public class ControlWinLose {
|
||||
|
||||
List<Card> compAntes = new ArrayList<Card>(loser.getCardsIn(ZoneType.Ante));
|
||||
Deck cDeck = match.getPlayersDeck(loser.getLobbyPlayer());
|
||||
Deck oDeck = match.getPlayersOriginalDeck(loser.getLobbyPlayer());
|
||||
|
||||
for (Card c : compAntes) {
|
||||
CardPrinted toRemove = CardDb.instance().getCard(c);
|
||||
cDeck.getMain().remove(toRemove);
|
||||
if ( cDeck != oDeck )
|
||||
oDeck.getMain().remove(toRemove);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -119,10 +119,6 @@ public class QuestWinLose extends ControlWinLose {
|
||||
qData.getCards().resetNewList();
|
||||
QuestController qc = Singletons.getModel().getQuest();
|
||||
|
||||
if (match.isMatchOver()) {
|
||||
restoreQuestDeckEdits();
|
||||
}
|
||||
|
||||
LobbyPlayer questPlayer = Singletons.getControl().getLobby().getQuestPlayer();
|
||||
if (isAnte) {
|
||||
//do per-game actions
|
||||
@@ -246,18 +242,6 @@ public class QuestWinLose extends ControlWinLose {
|
||||
new QuestWinLoseCardViewer(antesWon), QuestWinLose.CONSTRAINTS_CARDS);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* restoreQuestDeckEdits
|
||||
* </p>
|
||||
* Reverts the persistent sideboard changes in quest decks.
|
||||
*/
|
||||
private void restoreQuestDeckEdits() {
|
||||
for (LobbyPlayer p : Singletons.getModel().getMatch().getPlayers().keySet()) {
|
||||
Singletons.getModel().getMatch().getPlayersDeck(p).clearDeckEdits();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* actionOnQuit.
|
||||
|
||||
@@ -187,8 +187,8 @@ public class ItemPool<T extends InventoryItem> extends ItemPoolView<T> {
|
||||
* @param card
|
||||
* a T
|
||||
*/
|
||||
public void remove(final T card) {
|
||||
this.remove(card, 1);
|
||||
public boolean remove(final T card) {
|
||||
return this.remove(card, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -200,10 +200,10 @@ public class ItemPool<T extends InventoryItem> extends ItemPoolView<T> {
|
||||
* @param amount
|
||||
* a int
|
||||
*/
|
||||
public void remove(final T card, final int amount) {
|
||||
public boolean remove(final T card, final int amount) {
|
||||
final int count = this.count(card);
|
||||
if ((count == 0) || (amount <= 0)) {
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
if (count <= amount) {
|
||||
this.getCards().remove(card);
|
||||
@@ -211,6 +211,7 @@ public class ItemPool<T extends InventoryItem> extends ItemPoolView<T> {
|
||||
this.getCards().put(card, count - amount);
|
||||
}
|
||||
this.setListInSync(false);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -336,7 +336,6 @@ public final class QuestUtilCards {
|
||||
final int leftInPool = this.qa.getCardPool().count(card);
|
||||
// remove sold cards from all decks:
|
||||
for (final Deck deck : this.qc.getMyDecks()) {
|
||||
deck.clearDeckEdits();
|
||||
deck.getMain().remove(card, deck.getMain().count(card) - leftInPool);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -57,7 +57,6 @@ import forge.Singletons;
|
||||
import forge.card.CardEdition;
|
||||
import forge.deck.DeckSection;
|
||||
import forge.error.ErrorViewer;
|
||||
import forge.game.GameType;
|
||||
import forge.quest.data.GameFormatQuest;
|
||||
import forge.item.BoosterPack;
|
||||
import forge.item.CardDb;
|
||||
@@ -99,7 +98,6 @@ public class QuestDataIO {
|
||||
final XStream xStream = isIgnoring ? new IgnoringXStream() : new XStream();
|
||||
xStream.registerConverter(new ItemPoolToXml());
|
||||
xStream.registerConverter(new DeckSectionToXml());
|
||||
xStream.registerConverter(new GameTypeToXml());
|
||||
xStream.registerConverter(new GameFormatQuestToXml());
|
||||
xStream.registerConverter(new QuestModeToXml());
|
||||
xStream.autodetectAnnotations(true);
|
||||
@@ -447,25 +445,6 @@ public class QuestDataIO {
|
||||
}
|
||||
}
|
||||
|
||||
private static class GameTypeToXml implements Converter {
|
||||
@SuppressWarnings("rawtypes")
|
||||
@Override
|
||||
public boolean canConvert(final Class clasz) {
|
||||
return clasz.equals(GameType.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void marshal(final Object source, final HierarchicalStreamWriter writer, final MarshallingContext context) {
|
||||
// not used
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object unmarshal(final HierarchicalStreamReader reader, final UnmarshallingContext context) {
|
||||
final String value = reader.getValue();
|
||||
return GameType.smartValueOf(value, GameType.Quest);
|
||||
}
|
||||
}
|
||||
|
||||
private static class QuestModeToXml implements Converter {
|
||||
@SuppressWarnings("rawtypes")
|
||||
@Override
|
||||
|
||||
@@ -156,7 +156,7 @@ public class FileSection {
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public static Map<String, List<String>> parseSections(final List<String> source) {
|
||||
final Map<String, List<String>> result = new HashMap<String, List<String>>();
|
||||
final Map<String, List<String>> result = new TreeMap<String, List<String>>(String.CASE_INSENSITIVE_ORDER);
|
||||
String currentSection = "";
|
||||
List<String> currentList = null;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user