mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-18 19:58:00 +00:00
Merge branch 'token_scripts' into 'master'
Allow scripts to be written for Tokens See merge request core-developers/forge!236
This commit is contained in:
@@ -43,7 +43,7 @@ import java.util.zip.ZipFile;
|
||||
|
||||
import forge.util.BuildInfo;
|
||||
import org.apache.commons.lang3.time.StopWatch;
|
||||
|
||||
import com.google.common.io.Files;
|
||||
import forge.card.CardRules;
|
||||
import forge.util.FileUtil;
|
||||
import forge.util.Localizer;
|
||||
@@ -71,6 +71,7 @@ public class CardStorageReader {
|
||||
}
|
||||
|
||||
private static final String CARD_FILE_DOT_EXTENSION = ".txt";
|
||||
private static final String UPCOMING = "upcoming";
|
||||
|
||||
/** Default charset when loading from files. */
|
||||
public static final String DEFAULT_CHARSET_NAME = "UTF-8";
|
||||
@@ -80,6 +81,7 @@ public class CardStorageReader {
|
||||
|
||||
private final ProgressObserver progressObserver;
|
||||
|
||||
private final boolean loadingTokens;
|
||||
private transient File cardsfolder;
|
||||
|
||||
private transient ZipFile zip;
|
||||
@@ -91,6 +93,9 @@ public class CardStorageReader {
|
||||
public CardStorageReader(final String cardDataDir, final CardStorageReader.ProgressObserver progressObserver, boolean loadCardsLazily) {
|
||||
this.progressObserver = progressObserver != null ? progressObserver : CardStorageReader.ProgressObserver.emptyObserver;
|
||||
this.cardsfolder = new File(cardDataDir);
|
||||
|
||||
this.loadingTokens = cardDataDir.contains("token");
|
||||
|
||||
this.loadCardsLazily = loadCardsLazily;
|
||||
|
||||
// These read data for lightweight classes.
|
||||
@@ -240,6 +245,9 @@ public class CardStorageReader {
|
||||
final Set<CardRules> result = new TreeSet<>(new Comparator<CardRules>() {
|
||||
@Override
|
||||
public int compare(final CardRules o1, final CardRules o2) {
|
||||
if (loadingTokens) {
|
||||
return String.CASE_INSENSITIVE_ORDER.compare(o1.getNormalizedName(), o2.getNormalizedName());
|
||||
}
|
||||
return String.CASE_INSENSITIVE_ORDER.compare(o1.getName(), o2.getName());
|
||||
}
|
||||
});
|
||||
@@ -252,7 +260,7 @@ public class CardStorageReader {
|
||||
if (!allFiles.isEmpty()) {
|
||||
int fileParts = zip == null ? NUMBER_OF_PARTS : 1 + NUMBER_OF_PARTS / 3;
|
||||
if (allFiles.size() < fileParts * 100) {
|
||||
fileParts = allFiles.size() / 100; // to avoid creation of many threads for a dozen of files
|
||||
fileParts = Math.max(1, allFiles.size() / 100); // to avoid creation of many threads for a dozen of files
|
||||
}
|
||||
final CountDownLatch cdlFiles = new CountDownLatch(fileParts);
|
||||
final List<Callable<List<CardRules>>> taskFiles = makeTaskListForFiles(allFiles, cdlFiles);
|
||||
@@ -377,7 +385,7 @@ public class CardStorageReader {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (filename.equalsIgnoreCase("upcoming") && !BuildInfo.isDevelopmentVersion()) {
|
||||
if (filename.equalsIgnoreCase(CardStorageReader.UPCOMING) && !BuildInfo.isDevelopmentVersion()) {
|
||||
// If upcoming folder exits, only load these cards on development builds
|
||||
continue;
|
||||
}
|
||||
@@ -402,7 +410,7 @@ public class CardStorageReader {
|
||||
fileInputStream = new FileInputStream(file);
|
||||
reader.reset();
|
||||
final List<String> lines = readScript(fileInputStream);
|
||||
return reader.readCard(lines);
|
||||
return reader.readCard(lines, Files.getNameWithoutExtension(file.getName()));
|
||||
} catch (final FileNotFoundException ex) {
|
||||
throw new RuntimeException("CardReader : run error -- file not found: " + file.getPath(), ex);
|
||||
} finally {
|
||||
@@ -430,7 +438,7 @@ public class CardStorageReader {
|
||||
zipInputStream = this.zip.getInputStream(entry);
|
||||
rulesReader.reset();
|
||||
|
||||
return rulesReader.readCard(readScript(zipInputStream));
|
||||
return rulesReader.readCard(readScript(zipInputStream), Files.getNameWithoutExtension(entry.getName()));
|
||||
} catch (final IOException exn) {
|
||||
throw new RuntimeException(exn);
|
||||
// PM
|
||||
|
||||
@@ -9,6 +9,7 @@ import forge.item.BoosterBox;
|
||||
import forge.item.FatPack;
|
||||
import forge.item.PaperCard;
|
||||
import forge.item.SealedProduct;
|
||||
import forge.token.TokenDb;
|
||||
import forge.util.storage.IStorage;
|
||||
import forge.util.storage.StorageBase;
|
||||
|
||||
@@ -22,10 +23,13 @@ import java.util.*;
|
||||
* @author Max
|
||||
*/
|
||||
public class StaticData {
|
||||
private final CardStorageReader reader;
|
||||
private final CardStorageReader cardReader;
|
||||
private final CardStorageReader tokenReader;
|
||||
|
||||
private final String blockDataFolder;
|
||||
private final CardDb commonCards;
|
||||
private final CardDb variantCards;
|
||||
private final TokenDb allTokens;
|
||||
private final CardEdition.Collection editions;
|
||||
|
||||
// Loaded lazily:
|
||||
@@ -38,16 +42,22 @@ public class StaticData {
|
||||
|
||||
private static StaticData lastInstance = null;
|
||||
|
||||
public StaticData(CardStorageReader reader, String editionFolder, String blockDataFolder) {
|
||||
this.reader = reader;
|
||||
public StaticData(CardStorageReader cardReader, String editionFolder, String blockDataFolder) {
|
||||
this(cardReader, null, editionFolder, blockDataFolder);
|
||||
}
|
||||
|
||||
public StaticData(CardStorageReader cardReader, CardStorageReader tokenReader, String editionFolder, String blockDataFolder) {
|
||||
this.cardReader = cardReader;
|
||||
this.tokenReader = tokenReader;
|
||||
this.editions = new CardEdition.Collection(new CardEdition.Reader(new File(editionFolder)));
|
||||
this.blockDataFolder = blockDataFolder;
|
||||
lastInstance = this;
|
||||
|
||||
{
|
||||
final Map<String, CardRules> regularCards = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
|
||||
final Map<String, CardRules> variantsCards = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
|
||||
|
||||
for (CardRules card : reader.loadCards()) {
|
||||
for (CardRules card : cardReader.loadCards()) {
|
||||
if (null == card) continue;
|
||||
|
||||
final String cardName = card.getName();
|
||||
@@ -66,6 +76,18 @@ public class StaticData {
|
||||
variantCards.initialize(false, false);
|
||||
}
|
||||
|
||||
{
|
||||
final Map<String, CardRules> tokens = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
|
||||
|
||||
for (CardRules card : tokenReader.loadCards()) {
|
||||
if (null == card) continue;
|
||||
|
||||
tokens.put(card.getNormalizedName(), card);
|
||||
}
|
||||
allTokens = new TokenDb(tokens, editions);
|
||||
}
|
||||
}
|
||||
|
||||
public static StaticData instance() {
|
||||
return lastInstance;
|
||||
}
|
||||
@@ -91,7 +113,7 @@ public class StaticData {
|
||||
PaperCard card = commonCards.getCard(cardName, setCode, artIndex);
|
||||
if (card == null) {
|
||||
attemptToLoadCard(cardName, setCode);
|
||||
commonCards.getCard(cardName, setCode, artIndex);
|
||||
card = commonCards.getCard(cardName, setCode, artIndex);
|
||||
}
|
||||
if (card == null) {
|
||||
card = commonCards.getCard(cardName, setCode, -1);
|
||||
@@ -105,7 +127,7 @@ public class StaticData {
|
||||
public void attemptToLoadCard(String encodedCardName, String setCode) {
|
||||
CardDb.CardRequest r = CardRequest.fromString(encodedCardName);
|
||||
String cardName = r.cardName;
|
||||
CardRules rules = reader.attemptToLoadCard(cardName, setCode);
|
||||
CardRules rules = cardReader.attemptToLoadCard(cardName, setCode);
|
||||
if (rules != null) {
|
||||
if (rules.isVariant()) {
|
||||
variantCards.loadCard(cardName, rules);
|
||||
@@ -162,6 +184,8 @@ public class StaticData {
|
||||
return variantCards;
|
||||
}
|
||||
|
||||
public TokenDb getAllTokens() { return allTokens; }
|
||||
|
||||
public PaperCard getCardByEditionDate(PaperCard card, Date editionDate) {
|
||||
|
||||
PaperCard c = this.getCommonCards().getCardFromEdition(card.getName(), editionDate, CardDb.SetPreference.LatestCoreExp, card.getArtIndex());
|
||||
|
||||
@@ -74,6 +74,7 @@ public final class CardDb implements ICardDatabase, IDeckGenPool {
|
||||
|
||||
// NO GETTERS/SETTERS HERE!
|
||||
public static class CardRequest {
|
||||
// TODO Move Request to its own class
|
||||
public String cardName;
|
||||
public String edition;
|
||||
public int artIndex;
|
||||
|
||||
@@ -26,6 +26,7 @@ public enum CardRarity {
|
||||
Rare("R", "Rare"),
|
||||
MythicRare("M", "Mythic Rare"),
|
||||
Special("S", "Special"), // Timeshifted
|
||||
None("N", "None"), // Tokens
|
||||
Unknown("?", "Unknown"); // In development
|
||||
|
||||
public static final CardRarity[] FILTER_OPTIONS = new CardRarity[] {
|
||||
|
||||
@@ -34,6 +34,7 @@ import java.util.StringTokenizer;
|
||||
* @version $Id: CardRules.java 9708 2011-08-09 19:34:12Z jendave $
|
||||
*/
|
||||
public final class CardRules implements ICardCharacteristics {
|
||||
private String normalizedName;
|
||||
private CardSplitType splitType;
|
||||
private ICardFace mainPart;
|
||||
private ICardFace otherPart;
|
||||
@@ -124,6 +125,9 @@ public final class CardRules implements ICardCharacteristics {
|
||||
}
|
||||
}
|
||||
|
||||
public String getNormalizedName() { return normalizedName; }
|
||||
public void setNormalizedName(String filename) { normalizedName = filename; }
|
||||
|
||||
public CardAiHints getAiHints() {
|
||||
return aiHints;
|
||||
}
|
||||
@@ -207,12 +211,6 @@ public final class CardRules implements ICardCharacteristics {
|
||||
return meldWith;
|
||||
}
|
||||
|
||||
// public Set<String> getSets() { return this.setsPrinted.keySet(); }
|
||||
// public CardInSet getEditionInfo(final String setCode) {
|
||||
// final CardInSet result = this.setsPrinted.get(setCode);
|
||||
// return result; // if returns null, String.format("Card '%s' was never printed in set '%s'", this.getName(), setCode);
|
||||
// }
|
||||
|
||||
// vanguard card fields, they don't use sides.
|
||||
private int deltaHand;
|
||||
private int deltaLife;
|
||||
@@ -260,6 +258,7 @@ public final class CardRules implements ICardCharacteristics {
|
||||
private CardSplitType altMode = CardSplitType.None;
|
||||
private String meldWith = "";
|
||||
private String handLife = null;
|
||||
private String normalizedName = "";
|
||||
|
||||
// fields to build CardAiHints
|
||||
private boolean removedFromAIDecks = false;
|
||||
@@ -287,6 +286,7 @@ public final class CardRules implements ICardCharacteristics {
|
||||
this.hints = null;
|
||||
this.has = null;
|
||||
this.meldWith = "";
|
||||
this.normalizedName = "";
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -299,6 +299,8 @@ public final class CardRules implements ICardCharacteristics {
|
||||
faces[0].assignMissingFields();
|
||||
if (null != faces[1]) faces[1].assignMissingFields();
|
||||
final CardRules result = new CardRules(faces, altMode, cah);
|
||||
|
||||
result.setNormalizedName(this.normalizedName);
|
||||
result.meldWith = this.meldWith;
|
||||
result.setDlUrls(pictureUrl);
|
||||
if (StringUtils.isNotBlank(handLife))
|
||||
@@ -306,7 +308,7 @@ public final class CardRules implements ICardCharacteristics {
|
||||
return result;
|
||||
}
|
||||
|
||||
public final CardRules readCard(final Iterable<String> script) {
|
||||
public final CardRules readCard(final Iterable<String> script, String filename) {
|
||||
this.reset();
|
||||
for (String line : script) {
|
||||
if (line.isEmpty() || line.charAt(0) == '#') {
|
||||
@@ -314,9 +316,14 @@ public final class CardRules implements ICardCharacteristics {
|
||||
}
|
||||
this.parseLine(line);
|
||||
}
|
||||
this.normalizedName = filename;
|
||||
return this.getCard();
|
||||
}
|
||||
|
||||
public final CardRules readCard(final Iterable<String> script) {
|
||||
return readCard(script, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the line.
|
||||
*
|
||||
|
||||
@@ -4,10 +4,12 @@ import forge.ImageKeys;
|
||||
import forge.card.CardEdition;
|
||||
import forge.card.CardRarity;
|
||||
import forge.card.CardRules;
|
||||
import forge.card.ColorSet;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Locale;
|
||||
|
||||
|
||||
public class PaperToken implements InventoryItemFromSet, IPaperCard {
|
||||
private String name;
|
||||
private CardEdition edition;
|
||||
@@ -29,21 +31,91 @@ public class PaperToken implements InventoryItemFromSet, IPaperCard {
|
||||
return out.toString().toLowerCase(Locale.ENGLISH);
|
||||
}
|
||||
|
||||
public static String makeTokenFileName(String colors, int power, int toughness, String name) {
|
||||
return makeTokenFileName(colors, String.valueOf(power), String.valueOf(toughness), name);
|
||||
public static String makeTokenFileName(String colors, String power, String toughness, String types) {
|
||||
return makeTokenFileName(null, colors, power, toughness, types);
|
||||
}
|
||||
|
||||
public static String makeTokenFileName(String colors, String power, String toughness, String name) {
|
||||
StringBuilder fileName = new StringBuilder();
|
||||
fileName.append(colors).append('_').append(power).append('_').append(toughness).append('_').append(name);
|
||||
return makeTokenFileName(fileName.toString());
|
||||
public static String makeTokenFileName(String name, String colors, String power, String toughness, String types) {
|
||||
ArrayList<String> build = new ArrayList<>();
|
||||
if (name != null) {
|
||||
build.add(name);
|
||||
}
|
||||
|
||||
public PaperToken(final CardRules c, CardEdition edition0, final String imageFileName) {
|
||||
build.add(colors);
|
||||
|
||||
if (power != null && toughness != null) {
|
||||
build.add(power);
|
||||
build.add(toughness);
|
||||
}
|
||||
build.add(types);
|
||||
|
||||
String fileName = StringUtils.join(build, "_");
|
||||
return makeTokenFileName(fileName);
|
||||
}
|
||||
|
||||
public static String makeTokenFileName(final CardRules rules, CardEdition edition) {
|
||||
ArrayList<String> build = new ArrayList<>();
|
||||
|
||||
String subtypes = StringUtils.join(rules.getType().getSubtypes(), " ");
|
||||
if (!rules.getName().equals(subtypes)) {
|
||||
return makeTokenFileName(rules.getName());
|
||||
}
|
||||
|
||||
ColorSet colors = rules.getColor();
|
||||
|
||||
if (colors.isColorless()) {
|
||||
build.add("C");
|
||||
} else {
|
||||
String color = "";
|
||||
if (colors.hasWhite()) color += "W";
|
||||
if (colors.hasBlue()) color += "U";
|
||||
if (colors.hasBlack()) color += "B";
|
||||
if (colors.hasRed()) color += "R";
|
||||
if (colors.hasGreen()) color += "G";
|
||||
|
||||
build.add(color);
|
||||
}
|
||||
|
||||
if (rules.getPower() != null && rules.getToughness() != null) {
|
||||
build.add(rules.getPower());
|
||||
build.add(rules.getToughness());
|
||||
}
|
||||
|
||||
String cardTypes = "";
|
||||
if (rules.getType().isArtifact()) cardTypes += "A";
|
||||
if (rules.getType().isEnchantment()) cardTypes += "E";
|
||||
|
||||
if (!cardTypes.isEmpty()) {
|
||||
build.add(cardTypes);
|
||||
}
|
||||
|
||||
build.add(subtypes);
|
||||
|
||||
// Are these keywords sorted?
|
||||
for(String keyword : rules.getMainPart().getKeywords()) {
|
||||
build.add(keyword);
|
||||
}
|
||||
|
||||
build.add(edition.getCode());
|
||||
|
||||
// Should future image file names be all lower case? Instead of Up case sets?
|
||||
return StringUtils.join(build, "_").toLowerCase();
|
||||
}
|
||||
|
||||
public PaperToken(final CardRules c) { this(c, null, null); }
|
||||
public PaperToken(final CardRules c, final String fileName) { this(c, null, fileName); }
|
||||
public PaperToken(final CardRules c, CardEdition edition) { this(c, edition, null); }
|
||||
public PaperToken(final CardRules c, CardEdition edition0, String imageFileName) {
|
||||
this.card = c;
|
||||
this.name = c.getName();
|
||||
this.edition = edition0;
|
||||
this.imageFileName = String.format("%s%s", null == edition || CardEdition.UNKNOWN == edition ? "" : edition.getCode(), imageFileName);
|
||||
|
||||
if (imageFileName == null) {
|
||||
this.imageFileName = makeTokenFileName(c, edition0);
|
||||
} else {
|
||||
String formatEdition = null == edition || CardEdition.UNKNOWN == edition ? "" : edition.getCode();
|
||||
this.imageFileName = String.format("%s%s", formatEdition, imageFileName);
|
||||
}
|
||||
}
|
||||
|
||||
@Override public String getName() { return name; }
|
||||
@@ -54,7 +126,7 @@ public class PaperToken implements InventoryItemFromSet, IPaperCard {
|
||||
@Override public boolean isFoil() { return false; }
|
||||
@Override public CardRules getRules() { return card; }
|
||||
|
||||
@Override public CardRarity getRarity() { return CardRarity.Common; } // They don't have rarity though!
|
||||
@Override public CardRarity getRarity() { return CardRarity.None; }
|
||||
|
||||
// Unfortunately this is a property of token, cannot move it outside of class
|
||||
public String getImageFilename() { return imageFileName; }
|
||||
|
||||
32
forge-core/src/main/java/forge/token/ITokenDatabase.java
Normal file
32
forge-core/src/main/java/forge/token/ITokenDatabase.java
Normal file
@@ -0,0 +1,32 @@
|
||||
package forge.token;
|
||||
|
||||
import com.google.common.base.Predicate;
|
||||
import forge.card.CardDb;
|
||||
import forge.item.PaperToken;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
public interface ITokenDatabase extends Iterable<PaperToken> {
|
||||
PaperToken getToken(String tokenName);
|
||||
PaperToken getToken(String tokenName, String edition);
|
||||
PaperToken getToken(String tokenName, String edition, int artIndex);
|
||||
PaperToken getTokenFromEdition(String tokenName, CardDb.SetPreference fromSet);
|
||||
PaperToken getTokenFromEdition(String tokenName, Date printedBefore, CardDb.SetPreference fromSet);
|
||||
PaperToken getTokenFromEdition(String tokenName, Date printedBefore, CardDb.SetPreference fromSet, int artIndex);
|
||||
|
||||
PaperToken getFoiled(PaperToken cpi);
|
||||
|
||||
int getPrintCount(String tokenName, String edition);
|
||||
int getMaxPrintCount(String tokenName);
|
||||
|
||||
int getArtCount(String tokenName, String edition);
|
||||
|
||||
Collection<PaperToken> getUniqueTokens();
|
||||
List<PaperToken> getAllTokens();
|
||||
List<PaperToken> getAllTokens(String tokenName);
|
||||
List<PaperToken> getAllTokens(Predicate<PaperToken> predicate);
|
||||
|
||||
Predicate<? super PaperToken> wasPrintedInSets(List<String> allowedSetCodes);
|
||||
}
|
||||
121
forge-core/src/main/java/forge/token/TokenDb.java
Normal file
121
forge-core/src/main/java/forge/token/TokenDb.java
Normal file
@@ -0,0 +1,121 @@
|
||||
package forge.token;
|
||||
|
||||
import com.google.common.base.Predicate;
|
||||
import com.google.common.collect.Maps;
|
||||
import forge.card.*;
|
||||
import forge.item.PaperCard;
|
||||
import forge.item.PaperToken;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
public class TokenDb implements ITokenDatabase {
|
||||
// Expected naming convention of scripts
|
||||
// token_name
|
||||
// minor_demon
|
||||
// marit_lage
|
||||
// gold
|
||||
|
||||
// colors_power_toughness_cardtypes_sub_types_keywords
|
||||
// Some examples:
|
||||
// c_3_3_a_wurm_lifelink
|
||||
// w_2_2_knight_first_strike
|
||||
|
||||
// The image names should be the same as the script name + _set
|
||||
// If that isn't found, consider falling back to the original token
|
||||
|
||||
private final Map<String, PaperToken> tokensByName = Maps.newTreeMap(String.CASE_INSENSITIVE_ORDER);
|
||||
|
||||
private final CardEdition.Collection editions;
|
||||
private final Map<String, CardRules> rulesByName;
|
||||
|
||||
public TokenDb(Map<String, CardRules> rules, CardEdition.Collection editions) {
|
||||
this.rulesByName = rules;
|
||||
this.editions = editions;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PaperToken getToken(String tokenName) {
|
||||
return getToken(tokenName, CardEdition.UNKNOWN.getName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public PaperToken getToken(String tokenName, String edition) {
|
||||
try {
|
||||
PaperToken pt = new PaperToken(rulesByName.get(tokenName), editions.get(edition));
|
||||
// TODO Cache the token after it's referenced
|
||||
return pt;
|
||||
} catch(Exception e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public PaperToken getToken(String tokenName, String edition, int artIndex) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PaperToken getTokenFromEdition(String tokenName, CardDb.SetPreference fromSet) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PaperToken getTokenFromEdition(String tokenName, Date printedBefore, CardDb.SetPreference fromSet) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PaperToken getTokenFromEdition(String tokenName, Date printedBefore, CardDb.SetPreference fromSet, int artIndex) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PaperToken getFoiled(PaperToken cpi) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPrintCount(String cardName, String edition) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMaxPrintCount(String cardName) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getArtCount(String cardName, String edition) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<PaperToken> getUniqueTokens() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<PaperToken> getAllTokens() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<PaperToken> getAllTokens(String tokenName) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<PaperToken> getAllTokens(Predicate<PaperToken> predicate) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Predicate<? super PaperToken> wasPrintedInSets(List<String> allowedSetCodes) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<PaperToken> iterator() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -18,10 +18,13 @@
|
||||
package forge.game.ability.effects;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import forge.StaticData;
|
||||
import forge.card.MagicColor;
|
||||
import forge.game.card.token.TokenInfo;
|
||||
import forge.util.TextUtil;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import com.google.common.collect.Iterables;
|
||||
@@ -69,7 +72,23 @@ public class TokenEffect extends SpellAbilityEffect {
|
||||
private String[] tokenKeywords;
|
||||
private String[] tokenHiddenKeywords;
|
||||
|
||||
private void readParameters(final SpellAbility mapParams) {
|
||||
private void readMetaParams(final SpellAbility mapParams) {
|
||||
this.tokenTapped = mapParams.getParamOrDefault("TokenTapped", "False").equalsIgnoreCase("True");
|
||||
this.tokenAttacking = mapParams.getParamOrDefault("TokenAttacking", "False").equalsIgnoreCase("True");
|
||||
this.tokenBlocking = mapParams.getParam("TokenBlocking");
|
||||
|
||||
this.tokenAmount = mapParams.getParamOrDefault("TokenAmount", "1");
|
||||
this.tokenOwner = mapParams.getParamOrDefault("TokenOwner", "You");
|
||||
}
|
||||
|
||||
private void readParameters(final SpellAbility mapParams, Card prototype) {
|
||||
readMetaParams(mapParams);
|
||||
if (prototype == null) {
|
||||
readTokenParams(mapParams);
|
||||
}
|
||||
}
|
||||
|
||||
private void readTokenParams(final SpellAbility mapParams) {
|
||||
String image;
|
||||
String[] keywords;
|
||||
|
||||
@@ -99,9 +118,6 @@ public class TokenEffect extends SpellAbilityEffect {
|
||||
this.tokenAltImages = null;
|
||||
}
|
||||
|
||||
this.tokenTapped = mapParams.hasParam("TokenTapped") && mapParams.getParam("TokenTapped").equals("True");
|
||||
this.tokenAttacking = mapParams.hasParam("TokenAttacking") && mapParams.getParam("TokenAttacking").equals("True");
|
||||
|
||||
if (mapParams.hasParam("TokenAbilities")) {
|
||||
this.tokenAbilities = mapParams.getParam("TokenAbilities").split(",");
|
||||
} else {
|
||||
@@ -122,8 +138,7 @@ public class TokenEffect extends SpellAbilityEffect {
|
||||
} else {
|
||||
this.tokenStaticAbilities = null;
|
||||
}
|
||||
this.tokenBlocking = mapParams.getParam("TokenBlocking");
|
||||
this.tokenAmount = mapParams.getParamOrDefault("TokenAmount", "1");
|
||||
|
||||
this.tokenPower = mapParams.getParam("TokenPower");
|
||||
this.tokenToughness = mapParams.getParam("TokenToughness");
|
||||
|
||||
@@ -143,19 +158,19 @@ public class TokenEffect extends SpellAbilityEffect {
|
||||
|
||||
this.tokenKeywords = keywords;
|
||||
this.tokenImage = image;
|
||||
if (mapParams.hasParam("TokenOwner")) {
|
||||
this.tokenOwner = mapParams.getParam("TokenOwner");
|
||||
} else {
|
||||
this.tokenOwner = "You";
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getStackDescription(SpellAbility sa) {
|
||||
final StringBuilder sb = new StringBuilder();
|
||||
final Card host = sa.getHostCard();
|
||||
Card prototype = loadTokenPrototype(sa);
|
||||
|
||||
readParameters(sa);
|
||||
if (prototype != null) {
|
||||
return sa.getDescription();
|
||||
}
|
||||
|
||||
readParameters(sa, prototype);
|
||||
|
||||
final int finalPower = AbilityUtils.calculateAmount(host, this.tokenPower, sa);
|
||||
final int finalToughness = AbilityUtils.calculateAmount(host, this.tokenToughness, sa);
|
||||
@@ -181,11 +196,25 @@ public class TokenEffect extends SpellAbilityEffect {
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
private Card loadTokenPrototype(SpellAbility sa) {
|
||||
String script = sa.getParamOrDefault("TokenScript", null);
|
||||
|
||||
String edition = sa.getHostCard().getPaperCard().getEdition();
|
||||
|
||||
PaperToken token = StaticData.instance().getAllTokens().getToken(script, edition);
|
||||
if (token != null) {
|
||||
tokenName = token.getName();
|
||||
return Card.fromPaperCard(token, null, sa.getHostCard().getGame());
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void resolve(SpellAbility sa) {
|
||||
final Card host = sa.getHostCard();
|
||||
final Game game = host.getGame();
|
||||
final SpellAbility root = sa.getRootAbility();
|
||||
readParameters(sa);
|
||||
|
||||
// Cause of the Token Effect, in general it should be this
|
||||
// but if its a Replacement Effect, it might be something else or null
|
||||
@@ -194,30 +223,26 @@ public class TokenEffect extends SpellAbilityEffect {
|
||||
cause = (SpellAbility)root.getReplacingObject("Cause");
|
||||
}
|
||||
|
||||
String cost = "";
|
||||
final boolean remember = sa.hasParam("RememberTokens");
|
||||
final boolean imprint = sa.hasParam("ImprintTokens");
|
||||
final List<Card> allTokens = Lists.newArrayList();
|
||||
|
||||
// Construct original colors
|
||||
String originalColorDesc = "";
|
||||
for (final String col : this.tokenOriginalColors) {
|
||||
if (col.equalsIgnoreCase("White")) {
|
||||
originalColorDesc += "W ";
|
||||
} else if (col.equalsIgnoreCase("Blue")) {
|
||||
originalColorDesc += "U ";
|
||||
} else if (col.equalsIgnoreCase("Black")) {
|
||||
originalColorDesc += "B ";
|
||||
} else if (col.equalsIgnoreCase("Red")) {
|
||||
originalColorDesc += "R ";
|
||||
} else if (col.equalsIgnoreCase("Green")) {
|
||||
originalColorDesc += "G ";
|
||||
} else if (col.equalsIgnoreCase("Colorless")) {
|
||||
originalColorDesc = "C";
|
||||
}
|
||||
}
|
||||
boolean combatChanged = false;
|
||||
boolean inCombat = game.getPhaseHandler().inCombat();
|
||||
|
||||
Card prototype = loadTokenPrototype(sa);
|
||||
|
||||
readParameters(sa, prototype);
|
||||
final int finalAmount = AbilityUtils.calculateAmount(host, this.tokenAmount, sa);
|
||||
|
||||
TokenInfo tokenInfo;
|
||||
|
||||
if (prototype == null) {
|
||||
String originalColorDesc = parseColorForImage();
|
||||
|
||||
final List<String> imageNames = Lists.newArrayListWithCapacity(1);
|
||||
if (this.tokenImage.equals("")) {
|
||||
imageNames.add(PaperToken.makeTokenFileName(TextUtil.fastReplace(originalColorDesc,
|
||||
" ", ""), tokenPower, tokenToughness, tokenOriginalName));
|
||||
imageNames.add(PaperToken.makeTokenFileName(originalColorDesc, tokenPower, tokenToughness, tokenOriginalName));
|
||||
} else {
|
||||
imageNames.add(0, this.tokenImage);
|
||||
}
|
||||
@@ -225,38 +250,10 @@ public class TokenEffect extends SpellAbilityEffect {
|
||||
imageNames.addAll(Arrays.asList(this.tokenAltImages));
|
||||
}
|
||||
|
||||
final String[] substitutedColors = Arrays.copyOf(this.tokenColors, this.tokenColors.length);
|
||||
for (int i = 0; i < substitutedColors.length; i++) {
|
||||
if (substitutedColors[i].equals("ChosenColor")) {
|
||||
// this currently only supports 1 chosen color
|
||||
substitutedColors[i] = host.getChosenColor();
|
||||
}
|
||||
}
|
||||
String colorDesc = "";
|
||||
for (final String col : substitutedColors) {
|
||||
if (col.equalsIgnoreCase("White")) {
|
||||
colorDesc += "W ";
|
||||
} else if (col.equalsIgnoreCase("Blue")) {
|
||||
colorDesc += "U ";
|
||||
} else if (col.equalsIgnoreCase("Black")) {
|
||||
colorDesc += "B ";
|
||||
} else if (col.equalsIgnoreCase("Red")) {
|
||||
colorDesc += "R ";
|
||||
} else if (col.equalsIgnoreCase("Green")) {
|
||||
colorDesc += "G ";
|
||||
} else if (col.equalsIgnoreCase("Colorless")) {
|
||||
colorDesc = "C";
|
||||
}
|
||||
}
|
||||
for (final char c : colorDesc.toCharArray()) {
|
||||
cost += c + ' ';
|
||||
}
|
||||
|
||||
cost = colorDesc.replace('C', '1').trim();
|
||||
String cost = determineTokenColor(host);
|
||||
|
||||
final int finalPower = AbilityUtils.calculateAmount(host, this.tokenPower, sa);
|
||||
final int finalToughness = AbilityUtils.calculateAmount(host, this.tokenToughness, sa);
|
||||
final int finalAmount = AbilityUtils.calculateAmount(host, this.tokenAmount, sa);
|
||||
|
||||
final String[] substitutedTypes = Arrays.copyOf(this.tokenTypes, this.tokenTypes.length);
|
||||
for (int i = 0; i < substitutedTypes.length; i++) {
|
||||
@@ -266,120 +263,44 @@ public class TokenEffect extends SpellAbilityEffect {
|
||||
}
|
||||
final String substitutedName = this.tokenName.equals("ChosenType") ? host.getChosenType() : this.tokenName;
|
||||
|
||||
final boolean remember = sa.hasParam("RememberTokens");
|
||||
final boolean imprint = sa.hasParam("ImprintTokens");
|
||||
final List<Card> allTokens = Lists.newArrayList();
|
||||
for (final Player controller : AbilityUtils.getDefinedPlayers(host, this.tokenOwner, sa)) {
|
||||
final Game game = controller.getGame();
|
||||
for (int i = 0; i < finalAmount; i++) {
|
||||
final String imageName = imageNames.get(MyRandom.getRandom().nextInt(imageNames.size()));
|
||||
final TokenInfo tokenInfo = new TokenInfo(substitutedName, imageName,
|
||||
tokenInfo = new TokenInfo(substitutedName, imageName,
|
||||
cost, substitutedTypes, this.tokenKeywords, finalPower, finalToughness);
|
||||
final List<Card> tokens = tokenInfo.makeTokenWithMultiplier(controller, cause != null);
|
||||
|
||||
// Grant rule changes
|
||||
if (this.tokenHiddenKeywords != null) {
|
||||
for (final String s : this.tokenHiddenKeywords) {
|
||||
for (final Card c : tokens) {
|
||||
c.addHiddenExtrinsicKeyword(s);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
tokenInfo = new TokenInfo(prototype);
|
||||
}
|
||||
|
||||
// Grant SVars
|
||||
if (this.tokenSVars != null) {
|
||||
for (final String s : this.tokenSVars) {
|
||||
String actualSVar = AbilityUtils.getSVar(root, s);
|
||||
String name = s;
|
||||
if (actualSVar.startsWith("SVar")) {
|
||||
actualSVar = actualSVar.split("SVar:")[1];
|
||||
name = actualSVar.split(":")[0];
|
||||
actualSVar = actualSVar.split(":")[1];
|
||||
}
|
||||
for (final Card c : tokens) {
|
||||
c.setSVar(name, actualSVar);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (final Player controller : AbilityUtils.getDefinedPlayers(host, this.tokenOwner, sa)) {
|
||||
List<Card> tokens;
|
||||
|
||||
// Grant abilities
|
||||
if (this.tokenAbilities != null) {
|
||||
for (final String s : this.tokenAbilities) {
|
||||
final String actualAbility = AbilityUtils.getSVar(root, s);
|
||||
for (final Card c : tokens) {
|
||||
final SpellAbility grantedAbility = AbilityFactory.getAbility(actualAbility, c);
|
||||
// Set intrinsic, so that effects like Clone will copy these.
|
||||
grantedAbility.setIntrinsic(true);
|
||||
c.addSpellAbility(grantedAbility);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Grant triggers
|
||||
if (this.tokenTriggers != null) {
|
||||
for (final String s : this.tokenTriggers) {
|
||||
final String actualTrigger = AbilityUtils.getSVar(root, s);
|
||||
for (final Card c : tokens) {
|
||||
final Trigger parsedTrigger = TriggerHandler.parseTrigger(actualTrigger, c, true);
|
||||
final String ability = AbilityUtils.getSVar(root, parsedTrigger.getMapParams().get("Execute"));
|
||||
parsedTrigger.setOverridingAbility(AbilityFactory.getAbility(ability, c));
|
||||
c.addTrigger(parsedTrigger);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Grant static abilities
|
||||
if (this.tokenStaticAbilities != null) {
|
||||
for (final String s : this.tokenStaticAbilities) {
|
||||
final String actualAbility = AbilityUtils.getSVar(root, s);
|
||||
for (final Card c : tokens) {
|
||||
c.addStaticAbility(actualAbility);
|
||||
}
|
||||
}
|
||||
if (prototype == null) {
|
||||
tokens = tokenInfo.makeTokenWithMultiplier(controller, finalAmount, cause != null);
|
||||
grantHiddenKeywords(tokens);
|
||||
grantSvars(tokens, root);
|
||||
grantAbilities(tokens, root);
|
||||
grantTriggers(tokens, root);
|
||||
grantStatics(tokens, root);
|
||||
} else {
|
||||
tokens = TokenInfo.makeTokensFromPrototype(prototype, controller, finalAmount, cause != null);
|
||||
}
|
||||
|
||||
for (Card tok : tokens) {
|
||||
if (this.tokenTapped) {
|
||||
tok.setTapped(true);
|
||||
}
|
||||
game.getAction().moveToPlay(tok, sa);
|
||||
}
|
||||
game.fireEvent(new GameEventTokenCreated());
|
||||
// Should this be catching the Card that's returned?
|
||||
Card c = game.getAction().moveToPlay(tok, sa);
|
||||
|
||||
boolean combatChanged = false;
|
||||
for (final Card c : tokens) {
|
||||
if (sa.hasParam("AtEOTTrig")) {
|
||||
addSelfTrigger(sa, sa.getParam("AtEOTTrig"), c);
|
||||
}
|
||||
// To show the Abilities and Trigger on the Token
|
||||
|
||||
if (inCombat) {
|
||||
combatChanged = addTokenToCombat(game, c, controller, sa, host) || combatChanged;
|
||||
}
|
||||
|
||||
c.updateStateForView();
|
||||
if (this.tokenAttacking && game.getPhaseHandler().inCombat()) {
|
||||
final Combat combat = game.getCombat();
|
||||
|
||||
// into battlefield attacking only should work if you are the attacking player
|
||||
if (combat.getAttackingPlayer().equals(controller)) {
|
||||
final FCollectionView<GameEntity> defs = combat.getDefenders();
|
||||
final GameEntity defender = controller.getController().chooseSingleEntityForEffect(defs, sa, "Choose which defender to attack with " + c, false);
|
||||
combat.addAttacker(c, defender);
|
||||
combatChanged = true;
|
||||
}
|
||||
}
|
||||
if (this.tokenBlocking != null && game.getPhaseHandler().inCombat()) {
|
||||
final Combat combat = game.getPhaseHandler().getCombat();
|
||||
final Card attacker = Iterables.getFirst(AbilityUtils.getDefinedCards(host, this.tokenBlocking, sa), null);
|
||||
if (attacker != null) {
|
||||
final boolean wasBlocked = combat.isBlocked(attacker);
|
||||
combat.addBlocker(attacker, c);
|
||||
combat.orderAttackersForDamageAssignment(c);
|
||||
|
||||
// Run triggers for new blocker and add it to damage assignment order
|
||||
if (!wasBlocked) {
|
||||
combat.setBlocked(attacker, true);
|
||||
combat.addBlockerToDamageAssignmentOrder(attacker, c);
|
||||
}
|
||||
combatChanged = true;
|
||||
}
|
||||
}
|
||||
if (remember) {
|
||||
game.getCardState(sa.getHostCard()).addRemembered(c);
|
||||
}
|
||||
@@ -396,19 +317,154 @@ public class TokenEffect extends SpellAbilityEffect {
|
||||
token.addRemembered(o);
|
||||
}
|
||||
}
|
||||
allTokens.add(c);
|
||||
}
|
||||
if (tokenName.equals("Clue")) { // investigate trigger
|
||||
if ("Clue".equals(tokenName)) { // investigate trigger
|
||||
controller.addInvestigatedThisTurn();
|
||||
}
|
||||
}
|
||||
|
||||
game.fireEvent(new GameEventTokenCreated());
|
||||
|
||||
if (combatChanged) {
|
||||
game.updateCombatForView();
|
||||
game.fireEvent(new GameEventCombatChanged());
|
||||
}
|
||||
allTokens.addAll(tokens);
|
||||
}
|
||||
}
|
||||
if (sa.hasParam("AtEOT")) {
|
||||
registerDelayedTrigger(sa, sa.getParam("AtEOT"), allTokens);
|
||||
}
|
||||
}
|
||||
|
||||
private String parseColorForImage() {
|
||||
String originalColorDesc = "";
|
||||
for (final String col : this.tokenOriginalColors) {
|
||||
originalColorDesc += MagicColor.toShortString(col);
|
||||
if (originalColorDesc.equals("C")) {
|
||||
return originalColorDesc;
|
||||
}
|
||||
}
|
||||
return originalColorDesc;
|
||||
}
|
||||
|
||||
private String determineTokenColor(Card host) {
|
||||
Set<String> colorSet = new HashSet<>();
|
||||
final String[] substitutedColors = Arrays.copyOf(this.tokenColors, this.tokenColors.length);
|
||||
for (int i = 0; i < substitutedColors.length; i++) {
|
||||
if (substitutedColors[i].equals("ChosenColor")) {
|
||||
// this currently only supports 1 chosen color
|
||||
substitutedColors[i] = host.getChosenColor();
|
||||
}
|
||||
}
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (final String col : substitutedColors) {
|
||||
String str = MagicColor.toShortString(col);
|
||||
if (str.equals("C")) {
|
||||
return "1";
|
||||
}
|
||||
|
||||
sb.append(str).append(" ");
|
||||
}
|
||||
|
||||
return sb.toString().trim();
|
||||
}
|
||||
|
||||
private void grantHiddenKeywords(List<Card> tokens) {
|
||||
// Grant rule changes
|
||||
if (this.tokenHiddenKeywords != null) {
|
||||
for (final String s : this.tokenHiddenKeywords) {
|
||||
for (final Card c : tokens) {
|
||||
c.addHiddenExtrinsicKeyword(s);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void grantAbilities(List<Card> tokens, SpellAbility root) {
|
||||
if (this.tokenAbilities != null) {
|
||||
for (final String s : this.tokenAbilities) {
|
||||
final String actualAbility = AbilityUtils.getSVar(root, s);
|
||||
for (final Card c : tokens) {
|
||||
final SpellAbility grantedAbility = AbilityFactory.getAbility(actualAbility, c);
|
||||
// Set intrinsic, so that effects like Clone will copy these.
|
||||
grantedAbility.setIntrinsic(true);
|
||||
c.addSpellAbility(grantedAbility);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void grantTriggers(List<Card> tokens, SpellAbility root) {
|
||||
if (this.tokenTriggers != null) {
|
||||
for (final String s : this.tokenTriggers) {
|
||||
final String actualTrigger = AbilityUtils.getSVar(root, s);
|
||||
for (final Card c : tokens) {
|
||||
final Trigger parsedTrigger = TriggerHandler.parseTrigger(actualTrigger, c, true);
|
||||
final String ability = AbilityUtils.getSVar(root, parsedTrigger.getMapParams().get("Execute"));
|
||||
parsedTrigger.setOverridingAbility(AbilityFactory.getAbility(ability, c));
|
||||
c.addTrigger(parsedTrigger);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void grantSvars(List<Card> tokens, SpellAbility root) {
|
||||
if (this.tokenSVars != null) {
|
||||
for (final String s : this.tokenSVars) {
|
||||
String actualSVar = AbilityUtils.getSVar(root, s);
|
||||
String name = s;
|
||||
if (actualSVar.startsWith("SVar")) {
|
||||
actualSVar = actualSVar.split("SVar:")[1];
|
||||
name = actualSVar.split(":")[0];
|
||||
actualSVar = actualSVar.split(":")[1];
|
||||
}
|
||||
for (final Card c : tokens) {
|
||||
c.setSVar(name, actualSVar);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void grantStatics(List<Card> tokens, SpellAbility root) {
|
||||
if (this.tokenStaticAbilities != null) {
|
||||
for (final String s : this.tokenStaticAbilities) {
|
||||
final String actualAbility = AbilityUtils.getSVar(root, s);
|
||||
for (final Card c : tokens) {
|
||||
c.addStaticAbility(actualAbility);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean addTokenToCombat(Game game, Card c, Player controller, SpellAbility sa, Card host) {
|
||||
boolean combatChanged = false;
|
||||
if (this.tokenAttacking) {
|
||||
final Combat combat = game.getCombat();
|
||||
|
||||
// into battlefield attacking only should work if you are the attacking player
|
||||
if (combat.getAttackingPlayer().equals(controller)) {
|
||||
final FCollectionView<GameEntity> defs = combat.getDefenders();
|
||||
final GameEntity defender = controller.getController().chooseSingleEntityForEffect(defs, sa, "Choose which defender to attack with " + c, false);
|
||||
combat.addAttacker(c, defender);
|
||||
combatChanged = true;
|
||||
}
|
||||
}
|
||||
if (this.tokenBlocking != null) {
|
||||
final Combat combat = game.getPhaseHandler().getCombat();
|
||||
final Card attacker = Iterables.getFirst(AbilityUtils.getDefinedCards(host, this.tokenBlocking, sa), null);
|
||||
if (attacker != null) {
|
||||
final boolean wasBlocked = combat.isBlocked(attacker);
|
||||
combat.addBlocker(attacker, c);
|
||||
combat.orderAttackersForDamageAssignment(c);
|
||||
|
||||
// Run triggers for new blocker and add it to damage assignment order
|
||||
if (!wasBlocked) {
|
||||
combat.setBlocked(attacker, true);
|
||||
combat.addBlockerToDamageAssignmentOrder(attacker, c);
|
||||
}
|
||||
combatChanged = true;
|
||||
}
|
||||
}
|
||||
return combatChanged;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5405,6 +5405,9 @@ public class Card extends GameEntity implements Comparable<Card> {
|
||||
public static Card fromPaperCard(IPaperCard pc, Player owner) {
|
||||
return CardFactory.getCard(pc, owner, owner == null ? null : owner.getGame());
|
||||
}
|
||||
public static Card fromPaperCard(IPaperCard pc, Player owner, Game game) {
|
||||
return CardFactory.getCard(pc, owner, game);
|
||||
}
|
||||
|
||||
private static final Map<PaperCard, Card> cp2card = Maps.newHashMap();
|
||||
public static Card getCardForUi(IPaperCard pc) {
|
||||
|
||||
@@ -8,6 +8,7 @@ import forge.ImageKeys;
|
||||
import forge.card.CardType;
|
||||
import forge.game.Game;
|
||||
import forge.game.card.Card;
|
||||
import forge.game.card.CardFactory;
|
||||
import forge.game.card.CardFactoryUtil;
|
||||
import forge.game.keyword.KeywordInterface;
|
||||
import forge.game.player.Player;
|
||||
@@ -133,10 +134,7 @@ public class TokenInfo {
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public List<Card> makeTokenWithMultiplier(final Player controller, final boolean applyMultiplier) {
|
||||
final List<Card> list = Lists.newArrayList();
|
||||
final Game game = controller.getGame();
|
||||
|
||||
static private int calculateMultiplier(final Game game, final Player controller, final boolean applyMultiplier) {
|
||||
int multiplier = 1;
|
||||
Player player = controller;
|
||||
|
||||
@@ -155,12 +153,38 @@ public class TokenInfo {
|
||||
break;
|
||||
}
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
return multiplier;
|
||||
}
|
||||
|
||||
public List<Card> makeTokenWithMultiplier(final Player controller, int amount, final boolean applyMultiplier) {
|
||||
final List<Card> list = Lists.newArrayList();
|
||||
final Game game = controller.getGame();
|
||||
|
||||
int multiplier = calculateMultiplier(game, controller, applyMultiplier);
|
||||
|
||||
for (int i = 0; i < multiplier * amount; i++) {
|
||||
list.add(makeOneToken(controller));
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
for (int i = 0; i < multiplier; i++) {
|
||||
list.add(makeOneToken(player));
|
||||
static public List<Card> makeTokensFromPrototype(Card prototype, final Player controller, int amount, final boolean applyMultiplier) {
|
||||
final List<Card> list = Lists.newArrayList();
|
||||
final Game game = controller.getGame();
|
||||
|
||||
int multiplier = calculateMultiplier(game, controller, applyMultiplier);
|
||||
long timestamp = game.getNextTimestamp();
|
||||
prototype.setController(controller, timestamp);
|
||||
for (int i = 0; i < multiplier * amount; i++) {
|
||||
Card copy = CardFactory.copyCard(prototype, true);
|
||||
copy.setTimestamp(timestamp);
|
||||
copy.setOwner(controller);
|
||||
copy.setToken(true);
|
||||
list.add(copy);
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
|
||||
6
forge-gui/res/tokenscripts/c_3_3_a_wurm_deathtouch.txt
Normal file
6
forge-gui/res/tokenscripts/c_3_3_a_wurm_deathtouch.txt
Normal file
@@ -0,0 +1,6 @@
|
||||
Name:Wurm
|
||||
ManaCost:no cost
|
||||
Types:Artifact Creature Wurm
|
||||
PT:3/3
|
||||
K:Deathtouch
|
||||
Oracle:Deathtouch
|
||||
6
forge-gui/res/tokenscripts/c_3_3_a_wurm_lifelink.txt
Normal file
6
forge-gui/res/tokenscripts/c_3_3_a_wurm_lifelink.txt
Normal file
@@ -0,0 +1,6 @@
|
||||
Name:Wurm
|
||||
ManaCost:no cost
|
||||
Types:Artifact Creature Wurm
|
||||
PT:3/3
|
||||
K:Lifelink
|
||||
Oracle:Lifelink
|
||||
6
forge-gui/res/tokenscripts/voja.txt
Normal file
6
forge-gui/res/tokenscripts/voja.txt
Normal file
@@ -0,0 +1,6 @@
|
||||
Name:Voja
|
||||
ManaCost:no cost
|
||||
Types:Legendary Creature Wolf
|
||||
Colors:white,green
|
||||
PT:2/2
|
||||
Oracle:
|
||||
@@ -145,7 +145,9 @@ public final class FModel {
|
||||
|
||||
final CardStorageReader reader = new CardStorageReader(ForgeConstants.CARD_DATA_DIR, progressBarBridge,
|
||||
FModel.getPreferences().getPrefBoolean(FPref.LOAD_CARD_SCRIPTS_LAZILY));
|
||||
magicDb = new StaticData(reader, ForgeConstants.EDITIONS_DIR, ForgeConstants.BLOCK_DATA_DIR);
|
||||
final CardStorageReader tokenReader = new CardStorageReader(ForgeConstants.TOKEN_DATA_DIR, progressBarBridge,
|
||||
FModel.getPreferences().getPrefBoolean(FPref.LOAD_CARD_SCRIPTS_LAZILY));
|
||||
magicDb = new StaticData(reader, tokenReader, ForgeConstants.EDITIONS_DIR, ForgeConstants.BLOCK_DATA_DIR);
|
||||
|
||||
//create profile dirs if they don't already exist
|
||||
for (final String dname : ForgeConstants.PROFILE_DIRS) {
|
||||
|
||||
@@ -58,6 +58,7 @@ public final class ForgeConstants {
|
||||
public static final String DRAFT_RANKINGS_FILE = DRAFT_DIR + "rankings.txt";
|
||||
public static final String SEALED_DIR = RES_DIR + "sealed" + PATH_SEPARATOR;
|
||||
public static final String CARD_DATA_DIR = RES_DIR + "cardsfolder" + PATH_SEPARATOR;
|
||||
public static final String TOKEN_DATA_DIR = RES_DIR + "tokenscripts" + PATH_SEPARATOR;
|
||||
public static final String EDITIONS_DIR = RES_DIR + "editions" + PATH_SEPARATOR;
|
||||
public static final String BLOCK_DATA_DIR = RES_DIR + "blockdata" + PATH_SEPARATOR;
|
||||
public static final String DECK_CUBE_DIR = RES_DIR + "cube" + PATH_SEPARATOR;
|
||||
|
||||
Reference in New Issue
Block a user