CardEdition: add collector number for other (#7504)

* CardEdition: add collector number for other

* EditionEntry record

* Add getOtherImageKey

* Update StaticData.java

* use getOtherImageKey in getFacedownImageKey

* Update CardEdition.java

Remove findOther in favor of getOtherSet

* Update CardEdition.java

return findOther, but with Aggregates.random

* ~ move more helper images to ImageKeys
This commit is contained in:
Hans Mackowiak
2025-05-12 06:59:20 +02:00
committed by GitHub
parent 059881a7b5
commit cb0e594a6e
23 changed files with 206 additions and 193 deletions

View File

@@ -96,7 +96,7 @@ public class GameCopier {
newPlayer.setLandsPlayedThisTurn(origPlayer.getLandsPlayedThisTurn());
newPlayer.setCounters(Maps.newHashMap(origPlayer.getCounters()));
newPlayer.setSpeed(origPlayer.getSpeed());
newPlayer.setBlessing(origPlayer.hasBlessing());
newPlayer.setBlessing(origPlayer.hasBlessing(), null);
newPlayer.setRevolt(origPlayer.hasRevolt());
newPlayer.setDescended(origPlayer.getDescended());
newPlayer.setLibrarySearched(origPlayer.getLibrarySearched());

View File

@@ -23,10 +23,14 @@ public final class ImageKeys {
public static final String HIDDEN_CARD = "hidden";
public static final String MORPH_IMAGE = "morph";
public static final String DISGUISED_IMAGE = "disguised";
public static final String MANIFEST_IMAGE = "manifest";
public static final String CLOAKED_IMAGE = "cloaked";
public static final String FORETELL_IMAGE = "foretell";
public static final String BLESSING_IMAGE = "blessing";
public static final String INITIATIVE_IMAGE = "initiative";
public static final String MONARCH_IMAGE = "monarch";
public static final String THE_RING_IMAGE = "the_ring";
public static final String RADIATION_IMAGE = "radiation";
public static final String BACKFACE_POSTFIX = "$alt";
public static final String SPECFACE_W = "$wspec";

View File

@@ -95,12 +95,12 @@ public class StaticData {
if (!loadNonLegalCards) {
for (CardEdition e : editions) {
if (e.getType() == CardEdition.Type.FUNNY || e.getBorderColor() == CardEdition.BorderColor.SILVER) {
List<CardEdition.CardInSet> eternalCards = e.getFunnyEternalCards();
List<CardEdition.EditionEntry> eternalCards = e.getFunnyEternalCards();
for (CardEdition.CardInSet cis : e.getAllCardsInSet()) {
for (CardEdition.EditionEntry cis : e.getAllCardsInSet()) {
if (eternalCards.contains(cis))
continue;
funnyCards.add(cis.name);
funnyCards.add(cis.name());
}
}
}
@@ -790,11 +790,11 @@ public class StaticData {
Map<String, Pair<Boolean, Integer>> cardCount = new HashMap<>();
List<CompletableFuture<?>> futures = new ArrayList<>();
for (CardEdition.CardInSet c : e.getAllCardsInSet()) {
if (cardCount.containsKey(c.name)) {
cardCount.put(c.name, Pair.of(c.collectorNumber != null && c.collectorNumber.startsWith("F"), cardCount.get(c.name).getRight() + 1));
for (CardEdition.EditionEntry c : e.getAllCardsInSet()) {
if (cardCount.containsKey(c.name())) {
cardCount.put(c.name(), Pair.of(c.collectorNumber() != null && c.collectorNumber().startsWith("F"), cardCount.get(c.name()).getRight() + 1));
} else {
cardCount.put(c.name, Pair.of(c.collectorNumber != null && c.collectorNumber.startsWith("F"), 1));
cardCount.put(c.name(), Pair.of(c.collectorNumber() != null && c.collectorNumber().startsWith("F"), 1));
}
}
@@ -856,7 +856,7 @@ public class StaticData {
futures.clear();
// TODO: Audit token images here...
for(Map.Entry<String, Collection<CardEdition.TokenInSet>> tokenEntry : e.getTokens().asMap().entrySet()) {
for(Map.Entry<String, Collection<CardEdition.EditionEntry>> tokenEntry : e.getTokens().asMap().entrySet()) {
final String name = tokenEntry.getKey();
final int artIndex = tokenEntry.getValue().size();
try {
@@ -995,4 +995,23 @@ public class StaticData {
}
return false;
}
public String getOtherImageKey(String name, String set) {
if (this.editions.get(set) != null) {
String realSetCode = this.editions.get(set).getOtherSet(name);
if (realSetCode != null) {
CardEdition.EditionEntry ee = this.editions.get(realSetCode).findOther(name);
if (ee != null) { // TODO add collector Number and new ImageKey format
return ImageKeys.getTokenKey(name + "_" + realSetCode.toLowerCase());
}
}
}
for (CardEdition e : this.editions) {
CardEdition.EditionEntry ee = e.findOther(name);
if (ee != null) { // TODO add collector Number and new ImageKey format
return ImageKeys.getTokenKey(name + "_" + e.getCode().toLowerCase());
}
}
// final fallback
return ImageKeys.getTokenKey(name);
}
}

View File

@@ -22,7 +22,7 @@ import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Multimaps;
import forge.StaticData;
import forge.card.CardEdition.CardInSet;
import forge.card.CardEdition.EditionEntry;
import forge.card.CardEdition.Type;
import forge.deck.generation.IDeckGenPool;
import forge.item.IPaperCard;
@@ -332,27 +332,27 @@ public final class CardDb implements ICardDatabase, IDeckGenPool {
}
}
private void addSetCard(CardEdition e, CardInSet cis, CardRules cr) {
private void addSetCard(CardEdition e, EditionEntry cis, CardRules cr) {
int artIdx = IPaperCard.DEFAULT_ART_INDEX;
String key = e.getCode() + "/" + cis.name;
String key = e.getCode() + "/" + cis.name();
if (artIds.containsKey(key)) {
artIdx = artIds.get(key) + 1;
}
artIds.put(key, artIdx);
addCard(new PaperCard(cr, e.getCode(), cis.rarity, artIdx, false, cis.collectorNumber, cis.artistName, cis.functionalVariantName));
addCard(new PaperCard(cr, e.getCode(), cis.rarity(), artIdx, false, cis.collectorNumber(), cis.artistName(), cis.functionalVariantName()));
}
private boolean addFromSetByName(String cardName, CardEdition ed, CardRules cr) {
List<CardInSet> cardsInSet = ed.getCardInSet(cardName); // empty collection if not present
List<EditionEntry> cardsInSet = ed.getCardInSet(cardName); // empty collection if not present
if (cr.hasFunctionalVariants()) {
cardsInSet = cardsInSet.stream().filter(c -> StringUtils.isEmpty(c.functionalVariantName)
|| cr.getSupportedFunctionalVariants().contains(c.functionalVariantName)
cardsInSet = cardsInSet.stream().filter(c -> StringUtils.isEmpty(c.functionalVariantName())
|| cr.getSupportedFunctionalVariants().contains(c.functionalVariantName())
).collect(Collectors.toList());
}
if (cardsInSet.isEmpty())
return false;
for (CardInSet cis : cardsInSet) {
for (EditionEntry cis : cardsInSet) {
addSetCard(ed, cis, cr);
}
return true;
@@ -397,15 +397,15 @@ public final class CardDb implements ICardDatabase, IDeckGenPool {
upcomingSet = e;
}
for (CardEdition.CardInSet cis : e.getAllCardsInSet()) {
CardRules cr = rulesByName.get(cis.name);
for (CardEdition.EditionEntry cis : e.getAllCardsInSet()) {
CardRules cr = rulesByName.get(cis.name());
if (cr == null) {
missingCards.add(cis.name);
missingCards.add(cis.name());
continue;
}
if (cr.hasFunctionalVariants()) {
if (StringUtils.isNotEmpty(cis.functionalVariantName)
&& !cr.getSupportedFunctionalVariants().contains(cis.functionalVariantName)) {
if (StringUtils.isNotEmpty(cis.functionalVariantName())
&& !cr.getSupportedFunctionalVariants().contains(cis.functionalVariantName())) {
//Supported card, unsupported variant.
//Could note the card as missing but since these are often un-cards,
//it's likely absent because it does something out of scope.
@@ -463,8 +463,8 @@ public final class CardDb implements ICardDatabase, IDeckGenPool {
lang = new LangEnglish();
}
// for now just check Universes Within
for (CardInSet cis : editions.get("SLX").getCards()) {
String orgName = alternateName.get(cis.name);
for (EditionEntry cis : editions.get("SLX").getCards()) {
String orgName = alternateName.get(cis.name());
if (orgName != null) {
// found original (beyond) print
CardRules org = getRules(orgName);
@@ -494,7 +494,7 @@ public final class CardDb implements ICardDatabase, IDeckGenPool {
CardRules within = new CardRules(new ICardFace[] { renamedMain, renamedOther, null, null, null, null, null }, org.getSplitType(), org.getAiHints());
// so workshop can edit same script
within.setNormalizedName(org.getNormalizedName());
rulesByName.put(cis.name, within);
rulesByName.put(cis.name(), within);
}
}
}
@@ -1107,8 +1107,8 @@ public final class CardDb implements ICardDatabase, IDeckGenPool {
public Collection<PaperCard> getAllCards(CardEdition edition) {
List<PaperCard> cards = Lists.newArrayList();
for (CardInSet cis : edition.getAllCardsInSet()) {
PaperCard card = this.getCard(cis.name, edition.getCode());
for (EditionEntry cis : edition.getAllCardsInSet()) {
PaperCard card = this.getCard(cis.name(), edition.getCode());
if (card == null) {
// Just in case the card is listed in the edition file but Forge doesn't support it
continue;
@@ -1160,10 +1160,10 @@ public final class CardDb implements ICardDatabase, IDeckGenPool {
// May iterate over editions and find out if there is any card named 'cardRequest' but not implemented with Forge script.
if (StringUtils.isBlank(request.edition)) {
for (CardEdition edition : editions) {
for (CardInSet cardInSet : edition.getAllCardsInSet()) {
if (cardInSet.name.equals(request.cardName)) {
for (EditionEntry cardInSet : edition.getAllCardsInSet()) {
if (cardInSet.name().equals(request.cardName)) {
cardEdition = edition;
cardRarity = cardInSet.rarity;
cardRarity = cardInSet.rarity();
break;
}
}
@@ -1174,9 +1174,9 @@ public final class CardDb implements ICardDatabase, IDeckGenPool {
} else {
cardEdition = editions.get(request.edition);
if (cardEdition != null) {
for (CardInSet cardInSet : cardEdition.getAllCardsInSet()) {
if (cardInSet.name.equals(request.cardName)) {
cardRarity = cardInSet.rarity;
for (EditionEntry cardInSet : cardEdition.getAllCardsInSet()) {
if (cardInSet.name().equals(request.cardName)) {
cardRarity = cardInSet.rarity();
break;
}
}
@@ -1227,9 +1227,9 @@ public final class CardDb implements ICardDatabase, IDeckGenPool {
// @leriomaggio: DONE! re-using here the same strategy implemented for lazy-loading!
for (CardEdition e : editions.getOrderedEditions()) {
int artIdx = IPaperCard.DEFAULT_ART_INDEX;
for (CardInSet cis : e.getCardInSet(cardName))
paperCards.add(new PaperCard(rules, e.getCode(), cis.rarity, artIdx++, false,
cis.collectorNumber, cis.artistName, cis.functionalVariantName));
for (EditionEntry cis : e.getCardInSet(cardName))
paperCards.add(new PaperCard(rules, e.getCode(), cis.rarity(), artIdx++, false,
cis.collectorNumber(), cis.artistName(), cis.functionalVariantName()));
}
} else {
String lastEdition = null;
@@ -1243,13 +1243,13 @@ public final class CardDb implements ICardDatabase, IDeckGenPool {
if (ed == null) {
continue;
}
List<CardInSet> cardsInSet = ed.getCardInSet(cardName);
List<EditionEntry> cardsInSet = ed.getCardInSet(cardName);
if (cardsInSet.isEmpty())
continue;
int cardInSetIndex = Math.max(artIdx-1, 0); // make sure doesn't go below zero
CardInSet cds = cardsInSet.get(cardInSetIndex); // use ArtIndex to get the right Coll. Number
EditionEntry cds = cardsInSet.get(cardInSetIndex); // use ArtIndex to get the right Coll. Number
paperCards.add(new PaperCard(rules, lastEdition, tuple.getValue(), artIdx++, false,
cds.collectorNumber, cds.artistName, cds.functionalVariantName));
cds.collectorNumber(), cds.artistName(), cds.functionalVariantName()));
}
}
if (paperCards.isEmpty()) {

View File

@@ -18,6 +18,7 @@
package forge.card;
import com.google.common.collect.*;
import forge.StaticData;
import forge.card.CardDb.CardArtPreference;
import forge.deck.CardPool;
@@ -207,20 +208,7 @@ public final class CardEdition implements Comparable<CardEdition> {
return sortableCollNr;
}
public static class CardInSet implements Comparable<CardInSet> {
public final String collectorNumber;
public final String name;
public final String artistName;
public final CardRarity rarity;
public final String functionalVariantName;
public CardInSet(final String name, final String collectorNumber, final CardRarity rarity, final String artistName, final String functionalVariantName) {
this.name = name;
this.collectorNumber = collectorNumber;
this.artistName = artistName;
this.rarity = rarity;
this.functionalVariantName = functionalVariantName;
}
public record EditionEntry(String name, String collectorNumber, CardRarity rarity, String artistName, String functionalVariantName) implements Comparable<EditionEntry> {
public String toString() {
StringBuilder sb = new StringBuilder();
@@ -228,7 +216,7 @@ public final class CardEdition implements Comparable<CardEdition> {
sb.append(collectorNumber);
sb.append(' ');
}
if (rarity != CardRarity.Unknown) {
if (rarity != CardRarity.Unknown && rarity != CardRarity.Token) {
sb.append(rarity);
sb.append(' ');
}
@@ -245,7 +233,7 @@ public final class CardEdition implements Comparable<CardEdition> {
}
@Override
public int compareTo(CardInSet o) {
public int compareTo(EditionEntry o) {
final int nameCmp = name.compareToIgnoreCase(o.name);
if (0 != nameCmp) {
return nameCmp;
@@ -260,51 +248,13 @@ public final class CardEdition implements Comparable<CardEdition> {
}
}
public static class TokenInSet implements Comparable<TokenInSet> {
public final String collectorNumber;
public final String name;
public final String artistName;
public TokenInSet(final String name, final String collectorNumber, final String artistName) {
this.name = name;
this.collectorNumber = collectorNumber;
this.artistName = artistName;
}
public String toString() {
StringBuilder sb = new StringBuilder();
if (collectorNumber != null) {
sb.append(collectorNumber);
sb.append(' ');
}
sb.append(name);
if (artistName != null) {
sb.append(" @");
sb.append(artistName);
}
return sb.toString();
}
@Override
public int compareTo(TokenInSet o) {
final int nameCmp = name.compareToIgnoreCase(o.name);
if (0 != nameCmp) {
return nameCmp;
}
String thisCollNr = getSortableCollectorNumber(collectorNumber);
String othrCollNr = getSortableCollectorNumber(o.collectorNumber);
return thisCollNr.compareTo(othrCollNr);
}
}
private final static SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd");
/**
* Equivalent to the set code of CardEdition.UNKNOWN
*/
public static final String UNKNOWN_CODE = "???";
public static final CardEdition UNKNOWN = new CardEdition("1990-01-01", UNKNOWN_CODE, "??", Type.UNKNOWN, "Undefined", FoilType.NOT_SUPPORTED, new CardInSet[]{});
public static final CardEdition UNKNOWN = new CardEdition("1990-01-01", UNKNOWN_CODE, "??", Type.UNKNOWN, "Undefined", FoilType.NOT_SUPPORTED, new EditionEntry[]{});
private Date date;
private String code;
private String code2;
@@ -340,17 +290,18 @@ public final class CardEdition implements Comparable<CardEdition> {
private String doublePickDuringDraft = "";
private String[] chaosDraftThemes = new String[0];
private final ListMultimap<String, CardInSet> cardMap;
private final List<CardInSet> cardsInSet;
private final ListMultimap<String, TokenInSet> tokenMap;
private final ListMultimap<String, EditionEntry> cardMap;
private final List<EditionEntry> cardsInSet;
private final ListMultimap<String, EditionEntry> tokenMap;
// custom print sheets that will be loaded lazily
private final Map<String, List<String>> customPrintSheetsToParse;
private ListMultimap<String, EditionEntry> otherMap = ArrayListMultimap.create();
private int boosterArts = 1;
private SealedTemplate boosterTpl = null;
private final Map<String, SealedTemplate> boosterTemplates = new HashMap<>();
private CardEdition(ListMultimap<String, CardInSet> cardMap, ListMultimap<String, TokenInSet> tokens, Map<String, List<String>> customPrintSheetsToParse) {
private CardEdition(ListMultimap<String, EditionEntry> cardMap, ListMultimap<String, EditionEntry> tokens, Map<String, List<String>> customPrintSheetsToParse) {
this.cardMap = cardMap;
this.cardsInSet = new ArrayList<>(cardMap.values());
Collections.sort(cardsInSet);
@@ -358,8 +309,8 @@ public final class CardEdition implements Comparable<CardEdition> {
this.customPrintSheetsToParse = customPrintSheetsToParse;
}
private CardEdition(CardInSet[] cards, ListMultimap<String, TokenInSet> tokens) {
List<CardInSet> cardsList = Arrays.asList(cards);
private CardEdition(EditionEntry[] cards, ListMultimap<String, EditionEntry> tokens) {
List<EditionEntry> cardsList = Arrays.asList(cards);
this.cardMap = ArrayListMultimap.create();
this.cardMap.replaceValues("cards", cardsList);
this.cardsInSet = new ArrayList<>(cardsList);
@@ -381,7 +332,7 @@ public final class CardEdition implements Comparable<CardEdition> {
* @param name the name of the set
* @param cards the cards in the set
*/
private CardEdition(String date, String code, String code2, Type type, String name, FoilType foil, CardInSet[] cards) {
private CardEdition(String date, String code, String code2, Type type, String name, FoilType foil, EditionEntry[] cards) {
this(cards, ArrayListMultimap.create());
this.code = code;
this.code2 = code2;
@@ -430,14 +381,14 @@ public final class CardEdition implements Comparable<CardEdition> {
public String getSheetReplaceCardFromSheet2() { return sheetReplaceCardFromSheet2; }
public String[] getChaosDraftThemes() { return chaosDraftThemes; }
public List<CardInSet> getCards() { return cardMap.get(EditionSectionWithCollectorNumbers.CARDS.getName()); }
public List<CardInSet> getRebalancedCards() { return cardMap.get(EditionSectionWithCollectorNumbers.REBALANCED.getName()); }
public List<CardInSet> getFunnyEternalCards() { return cardMap.get(EditionSectionWithCollectorNumbers.ETERNAL.getName()); }
public List<CardInSet> getAllCardsInSet() {
public List<EditionEntry> getCards() { return cardMap.get(EditionSectionWithCollectorNumbers.CARDS.getName()); }
public List<EditionEntry> getRebalancedCards() { return cardMap.get(EditionSectionWithCollectorNumbers.REBALANCED.getName()); }
public List<EditionEntry> getFunnyEternalCards() { return cardMap.get(EditionSectionWithCollectorNumbers.ETERNAL.getName()); }
public List<EditionEntry> getAllCardsInSet() {
return cardsInSet;
}
private ListMultimap<String, CardInSet> cardsInSetLookupMap = null;
private ListMultimap<String, EditionEntry> cardsInSetLookupMap = null;
/**
* Get all the CardInSet instances with the input card name.
@@ -445,12 +396,12 @@ public final class CardEdition implements Comparable<CardEdition> {
* @return A List of all the CardInSet instances for a given name.
* If not fount, an Empty sequence (view) will be returned instead!
*/
public List<CardInSet> getCardInSet(String cardName){
public List<EditionEntry> getCardInSet(String cardName){
if (cardsInSetLookupMap == null) {
// initialise
cardsInSetLookupMap = Multimaps.newListMultimap(new TreeMap<>(String.CASE_INSENSITIVE_ORDER), Lists::newArrayList);
List<CardInSet> cardsInSet = this.getAllCardsInSet();
for (CardInSet cis : cardsInSet){
List<EditionEntry> cardsInSet = this.getAllCardsInSet();
for (EditionEntry cis : cardsInSet){
String key = cis.name;
cardsInSetLookupMap.put(key, cis);
}
@@ -458,10 +409,10 @@ public final class CardEdition implements Comparable<CardEdition> {
return this.cardsInSetLookupMap.get(cardName);
}
public CardInSet getCardFromCollectorNumber(String collectorNumber) {
public EditionEntry getCardFromCollectorNumber(String collectorNumber) {
if(collectorNumber == null || collectorNumber.isEmpty())
return null;
for(CardInSet c : this.cardsInSet) {
for(EditionEntry c : this.cardsInSet) {
//Could build a map for this one too if it's used for more than one-offs.
if (c.collectorNumber.equalsIgnoreCase(collectorNumber))
return c;
@@ -470,7 +421,7 @@ public final class CardEdition implements Comparable<CardEdition> {
}
public boolean isRebalanced(String cardName) {
for (CardInSet cis : getRebalancedCards()) {
for (EditionEntry cis : getRebalancedCards()) {
if (cis.name.equals(cardName)) {
return true;
}
@@ -480,7 +431,7 @@ public final class CardEdition implements Comparable<CardEdition> {
public boolean isModern() { return getDate().after(parseDate("2003-07-27")); } //8ED and above are modern except some promo cards and others
public Multimap<String, TokenInSet> getTokens() { return tokenMap; }
public Multimap<String, EditionEntry> getTokens() { return tokenMap; }
public String getTokenSet(String token) {
if (tokenMap.containsKey(token)) {
@@ -491,6 +442,22 @@ public final class CardEdition implements Comparable<CardEdition> {
}
return null;
}
public String getOtherSet(String token) {
if (otherMap.containsKey(token)) {
return this.getCode();
}
if (this.tokenFallbackCode != null) {
return StaticData.instance().getCardEdition(this.tokenFallbackCode).getOtherSet(token);
}
return null;
}
public EditionEntry findOther(String name) {
if (otherMap.containsKey(name)) {
return Aggregates.random(otherMap.get(name));
}
return null;
}
@Override
public int compareTo(final CardEdition o) {
@@ -574,8 +541,8 @@ public final class CardEdition implements Comparable<CardEdition> {
for (String sectionName : cardMap.keySet()) {
PrintSheet sheet = new PrintSheet(String.format("%s %s", this.getCode(), sectionName));
List<CardInSet> cards = cardMap.get(sectionName);
for (CardInSet card : cards) {
List<EditionEntry> cards = cardMap.get(sectionName);
for (EditionEntry card : cards) {
int index = 1;
if (cardToIndex.containsKey(card.name)) {
index = cardToIndex.get(card.name) + 1;
@@ -654,7 +621,7 @@ public final class CardEdition implements Comparable<CardEdition> {
"(^(.?[0-9A-Z]+\\S?[A-Z]*)\\s)?([^@]*)( @(.*))?$"
);
ListMultimap<String, CardInSet> cardMap = ArrayListMultimap.create();
ListMultimap<String, EditionEntry> cardMap = ArrayListMultimap.create();
List<BoosterSlot> boosterSlots = null;
Map<String, List<String>> customPrintSheetsToParse = new HashMap<>();
List<String> editionSectionsWithCollectorNumbers = EditionSectionWithCollectorNumbers.getNames();
@@ -686,7 +653,7 @@ public final class CardEdition implements Comparable<CardEdition> {
String cardName = matcher.group(5);
String artistName = matcher.group(7);
String functionalVariantName = matcher.group(9);
CardInSet cis = new CardInSet(cardName, collectorNumber, r, artistName, functionalVariantName);
EditionEntry cis = new EditionEntry(cardName, collectorNumber, r, artistName, functionalVariantName);
cardMap.put(sectionName, cis);
}
@@ -700,7 +667,8 @@ public final class CardEdition implements Comparable<CardEdition> {
}
}
ListMultimap<String, TokenInSet> tokenMap = ArrayListMultimap.create();
ListMultimap<String, EditionEntry> tokenMap = ArrayListMultimap.create();
ListMultimap<String, EditionEntry> otherMap = ArrayListMultimap.create();
// parse tokens section
if (contents.containsKey("tokens")) {
for (String line : contents.get("tokens")) {
@@ -715,10 +683,27 @@ public final class CardEdition implements Comparable<CardEdition> {
String collectorNumber = matcher.group(2);
String cardName = matcher.group(3);
String artistName = matcher.group(5);
TokenInSet tis = new TokenInSet(cardName, collectorNumber, artistName);
// rarity isn't used for this anyway
EditionEntry tis = new EditionEntry(cardName, collectorNumber, CardRarity.Token, artistName, null);
tokenMap.put(cardName, tis);
}
}
if (contents.containsKey("other")) {
for (String line : contents.get("other")) {
if (StringUtils.isBlank(line))
continue;
Matcher matcher = tokenPattern.matcher(line);
if (!matcher.matches()) {
continue;
}
String collectorNumber = matcher.group(2);
String cardName = matcher.group(3);
String artistName = matcher.group(5);
EditionEntry tis = new EditionEntry(cardName, collectorNumber, CardRarity.Unknown, artistName, null);
otherMap.put(cardName, tis);
}
}
CardEdition res = new CardEdition(cardMap, tokenMap, customPrintSheetsToParse);
res.boosterSlots = boosterSlots;
@@ -733,6 +718,8 @@ public final class CardEdition implements Comparable<CardEdition> {
res.cardsLanguage = metadata.get("CardLang", "en");
res.boosterArts = metadata.getInt("BoosterCovers", 1);
res.otherMap = otherMap;
String boosterDesc = metadata.get("Booster");
if (metadata.contains("Booster")) {
@@ -851,7 +838,7 @@ public final class CardEdition implements Comparable<CardEdition> {
initAliases(E); //Made a method in case the system changes, so it's consistent.
}
CardEdition customBucket = new CardEdition("2990-01-01", "USER", "USER",
Type.CUSTOM_SET, "USER", FoilType.NOT_SUPPORTED, new CardInSet[]{});
Type.CUSTOM_SET, "USER", FoilType.NOT_SUPPORTED, new EditionEntry[]{});
this.add(customBucket);
initAliases(customBucket);
this.lock = true; //Consider it initialized and prevent from writing any more data.

View File

@@ -958,9 +958,9 @@ public class Game {
// if the player who lost was the Monarch, someone else will be the monarch
// TODO need to check rules if it should try the next player if able
if (p.equals(getPhaseHandler().getPlayerTurn())) {
getAction().becomeMonarch(getNextPlayerAfter(p), null);
getAction().becomeMonarch(getNextPlayerAfter(p), p.getMonarchSet());
} else {
getAction().becomeMonarch(getPhaseHandler().getPlayerTurn(), null);
getAction().becomeMonarch(getPhaseHandler().getPlayerTurn(), p.getMonarchSet());
}
}
@@ -970,9 +970,9 @@ public class Game {
// If the player who has the initiative leaves the game on their own turn,
// or the active player left the game at the same time, the next player in turn order takes the initiative.
if (p.equals(getPhaseHandler().getPlayerTurn())) {
getAction().takeInitiative(getNextPlayerAfter(p), null);
getAction().takeInitiative(getNextPlayerAfter(p), p.getInitiativeSet());
} else {
getAction().takeInitiative(getPhaseHandler().getPlayerTurn(), null);
getAction().takeInitiative(getPhaseHandler().getPlayerTurn(), p.getInitiativeSet());
}
}

View File

@@ -21,7 +21,7 @@ import com.google.common.collect.Lists;
import forge.StaticData;
import forge.card.CardDb;
import forge.card.CardEdition;
import forge.card.CardEdition.CardInSet;
import forge.card.CardEdition.EditionEntry;
import forge.card.CardRarity;
import forge.deck.CardPool;
import forge.deck.Deck;
@@ -226,9 +226,9 @@ public class GameFormat implements Comparable<GameFormat> {
for (String setCode : allowedSetCodes_ro) {
CardEdition edition = StaticData.instance().getEditions().get(setCode);
if (edition != null) {
for (CardInSet card : edition.getAllCardsInSet()) {
if (!bannedCardNames_ro.contains(card.name)) {
PaperCard pc = commonCards.getCard(card.name, setCode, card.collectorNumber);
for (EditionEntry card : edition.getAllCardsInSet()) {
if (!bannedCardNames_ro.contains(card.name())) {
PaperCard pc = commonCards.getCard(card.name(), setCode, card.collectorNumber());
if (pc != null) {
cards.add(pc);
}

View File

@@ -170,7 +170,7 @@ public class GameSnapshot {
newPlayer.setDamageReceivedThisTurn(origPlayer.getDamageReceivedThisTurn());
newPlayer.setLandsPlayedThisTurn(origPlayer.getLandsPlayedThisTurn());
newPlayer.setCounters(Maps.newHashMap(origPlayer.getCounters()));
newPlayer.setBlessing(origPlayer.hasBlessing());
newPlayer.setBlessing(origPlayer.hasBlessing(), null);
newPlayer.setRevolt(origPlayer.hasRevolt());
newPlayer.setLibrarySearched(origPlayer.getLibrarySearched());
newPlayer.setSpellsCastLastTurn(origPlayer.getSpellsCastLastTurn());

View File

@@ -1366,7 +1366,7 @@ public class AbilityUtils {
// do blessing there before condition checks
if (source.hasKeyword(Keyword.ASCEND) && controller.getZone(ZoneType.Battlefield).size() >= 10) {
controller.setBlessing(true);
controller.setBlessing(true, source.getSetCode());
}
if (source.hasKeyword(Keyword.GIFT) && sa.isGiftPromised()) {

View File

@@ -39,7 +39,7 @@ public class AscendEffect extends SpellAbilityEffect {
}
// Player need 10+ permanents on the battlefield
if (p.getZone(ZoneType.Battlefield).size() >= 10) {
p.setBlessing(true);
p.setBlessing(true, sa.getOriginalHost().getSetCode());
}
}
}

View File

@@ -24,7 +24,7 @@ public class BecomeMonarchEffect extends SpellAbilityEffect {
@Override
public void resolve(SpellAbility sa) {
// TODO: improve ai and fix corner cases
final String set = sa.getHostCard().getSetCode();
final String set = sa.getOriginalHost().getSetCode();
for (final Player p : getTargetPlayers(sa)) {
if (!p.isInGame()) {

View File

@@ -71,7 +71,7 @@ public class RestartGameEffect extends SpellAbilityEffect {
p.resetRingTemptedYou();
p.clearRingBearer();
p.clearTheRing();
p.setBlessing(false);
p.setBlessing(false, null);
p.clearController();
CardCollection newLibrary = new CardCollection(p.getCardsIn(restartZones, false));

View File

@@ -23,10 +23,9 @@ public class RingTemptsYouEffect extends EffectEffect {
public void resolve(SpellAbility sa) {
Player p = sa.getActivatingPlayer();
Game game = p.getGame();
Card card = sa.getHostCard();
if (p.getTheRing() == null)
p.createTheRing(card);
p.createTheRing(sa.getOriginalHost().getSetCode());
//increment ring tempted you for property
p.incrementRingTemptedYou();

View File

@@ -24,7 +24,7 @@ public class TakeInitiativeEffect extends SpellAbilityEffect {
@Override
public void resolve(SpellAbility sa) {
// TODO: improve ai and fix corner cases
final String set = sa.getHostCard().getSetCode();
final String set = sa.getOriginalHost().getSetCode();
for (final Player p : getTargetPlayers(sa)) {
if (!p.isInGame()) {

View File

@@ -6549,28 +6549,31 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars, ITr
public final String getFacedownImageKey() {
if (isInZone(ZoneType.Exile)) {
return isForetold() ? ImageKeys.FORETELL_IMAGE : ImageKeys.HIDDEN_CARD;
if (isForetold()) {
return StaticData.instance().getOtherImageKey(ImageKeys.FORETELL_IMAGE, null);
}
return ImageKeys.getTokenKey(ImageKeys.HIDDEN_CARD);
}
if (isManifested()) {
String set = getManifestedSA().getCardState().getSetCode();
return ImageKeys.MANIFEST_IMAGE + "_" + set;
return StaticData.instance().getOtherImageKey(ImageKeys.MANIFEST_IMAGE, set);
}
if (isCloaked()) {
String set = getCloakedSA().getCardState().getSetCode();
return ImageKeys.CLOAKED_IMAGE + "_" + set;
return StaticData.instance().getOtherImageKey(ImageKeys.CLOAKED_IMAGE, set);
}
if (getCastSA() != null) {
String set = getCastSA().getCardState().getSetCode();
if (getCastSA().isKeyword(Keyword.DISGUISE)) {
return ImageKeys.CLOAKED_IMAGE + "_" + set;
return StaticData.instance().getOtherImageKey(ImageKeys.CLOAKED_IMAGE, set);
} else if (getCastSA().isKeyword(Keyword.MORPH) || getCastSA().isKeyword(Keyword.MEGAMORPH)) {
return ImageKeys.MORPH_IMAGE + "_" + set;
return StaticData.instance().getOtherImageKey(ImageKeys.MORPH_IMAGE, set);
}
}
// TODO add face-down SA to key
return ImageKeys.HIDDEN_CARD;
return ImageKeys.getTokenKey(ImageKeys.HIDDEN_CARD);
}
public final boolean isTributed() { return tributed; }

View File

@@ -1313,7 +1313,7 @@ public class CardView extends GameEntityView {
}
public String getImageKey(Iterable<PlayerView> viewers) {
if (getState() == CardStateName.FaceDown) {
return ImageKeys.getTokenKey(getCard().getFacedownImageKey());
return getCard().getFacedownImageKey();
}
if (canBeShownToAny(viewers)) {
if (isCloned() && StaticData.instance().useSourceImageForClone()) {

View File

@@ -20,6 +20,7 @@ package forge.game.player;
import com.google.common.collect.*;
import forge.ImageKeys;
import forge.LobbyPlayer;
import forge.StaticData;
import forge.card.*;
import forge.card.mana.ManaCost;
import forge.card.mana.ManaCostShard;
@@ -3303,18 +3304,15 @@ public class Player extends GameEntity implements Comparable<Player> {
this.updateZoneForView(com);
}
public void createTheRing(Card host) {
public void createTheRing(String set) {
final PlayerZone com = getZone(ZoneType.Command);
if (theRing == null) {
theRing = new Card(game.nextCardId(), null, game);
theRing.setOwner(this);
theRing.setGamePieceType(GamePieceType.EFFECT);
String image = ImageKeys.getTokenKey("the_ring");
if (host != null) {
theRing.setImageKey("t:the_ring_" + host.getSetCode().toLowerCase());
theRing.setSetCode(host.getSetCode());
} else {
theRing.setImageKey(image);
theRing.setImageKey(StaticData.instance().getOtherImageKey(ImageKeys.THE_RING_IMAGE, set));
if (set != null) {
theRing.setSetCode(set);
}
theRing.setName("The Ring");
theRing.updateStateForView();
@@ -3444,18 +3442,18 @@ public class Player extends GameEntity implements Comparable<Player> {
return equals(game.getMonarch());
}
public String getMonarchSet() {
return monarchEffect == null ? monarchEffect.getSetCode() : null;
}
public void createMonarchEffect(final String set) {
final PlayerZone com = getZone(ZoneType.Command);
if (monarchEffect == null) {
monarchEffect = new Card(game.nextCardId(), null, game);
monarchEffect.setOwner(this);
monarchEffect.setGamePieceType(GamePieceType.EFFECT);
if (set != null) {
monarchEffect.setImageKey("t:monarch_" + set.toLowerCase());
monarchEffect.setSetCode(set);
} else {
monarchEffect.setImageKey("t:monarch");
}
monarchEffect.setImageKey(StaticData.instance().getOtherImageKey(ImageKeys.MONARCH_IMAGE, set));
monarchEffect.setSetCode(set);
monarchEffect.setName("The Monarch");
{
@@ -3496,18 +3494,18 @@ public class Player extends GameEntity implements Comparable<Player> {
return !StaticAbilityCantBecomeMonarch.anyCantBecomeMonarch(this);
}
public String getInitiativeSet() {
return initiativeEffect != null ? initiativeEffect.getSetCode() : null;
}
public void createInitiativeEffect(final String set) {
final PlayerZone com = getZone(ZoneType.Command);
if (initiativeEffect == null) {
initiativeEffect = new Card(game.nextCardId(), null, game);
initiativeEffect.setOwner(this);
initiativeEffect.setGamePieceType(GamePieceType.EFFECT);
if (set != null) {
initiativeEffect.setImageKey("t:initiative_" + set.toLowerCase());
initiativeEffect.setSetCode(set);
} else {
initiativeEffect.setImageKey("t:initiative");
}
initiativeEffect.setImageKey(StaticData.instance().getOtherImageKey(ImageKeys.INITIATIVE_IMAGE, set));
initiativeEffect.setSetCode(set);
initiativeEffect.setName("The Initiative");
//Set up damage trigger
@@ -3574,7 +3572,7 @@ public class Player extends GameEntity implements Comparable<Player> {
radiationEffect = new Card(game.nextCardId(), null, game);
radiationEffect.setOwner(this);
radiationEffect.setGamePieceType(GamePieceType.EFFECT);
radiationEffect.setImageKey("t:radiation");
radiationEffect.setImageKey(StaticData.instance().getOtherImageKey(ImageKeys.RADIATION_IMAGE, setCode));
radiationEffect.setName("Radiation");
if (setCode != null) {
radiationEffect.setSetCode(setCode);
@@ -3684,7 +3682,7 @@ public class Player extends GameEntity implements Comparable<Player> {
public boolean hasBlessing() {
return blessingEffect != null;
}
public void setBlessing(boolean bless) {
public void setBlessing(boolean bless, String setCode) {
// no need to to change
if ((blessingEffect != null) == bless) {
return;
@@ -3695,9 +3693,12 @@ public class Player extends GameEntity implements Comparable<Player> {
if (bless) {
blessingEffect = new Card(game.nextCardId(), null, game);
blessingEffect.setOwner(this);
blessingEffect.setImageKey("t:blessing");
blessingEffect.setImageKey(StaticData.instance().getOtherImageKey(ImageKeys.BLESSING_IMAGE, setCode));
blessingEffect.setName("City's Blessing");
blessingEffect.setGamePieceType(GamePieceType.EFFECT);
if (setCode != null) {
blessingEffect.setSetCode(setCode);
}
blessingEffect.updateStateForView();

View File

@@ -241,7 +241,7 @@ public class RewardData implements Serializable {
{
allEditions.removeIf(
cardEdition -> cardEdition.getAllCardsInSet().stream().anyMatch(
o -> o.name.equals(restrictedCard))
o -> o.name().equals(restrictedCard))
);
}

View File

@@ -16,7 +16,7 @@ import forge.adventure.data.RewardData;
import forge.adventure.util.*;
import forge.card.CardEdition;
import forge.card.ColorSet;
import forge.card.CardEdition.CardInSet;
import forge.card.CardEdition.EditionEntry;
import forge.card.CardRarity;
import forge.item.PaperCard;
import forge.model.FModel;
@@ -356,9 +356,9 @@ public class SpellSmithScene extends UIScene {
// Use the rarity of the card from the filtered set.
CardRarity inputRarity = input.getRarity();
if (cardEdition != null) {
List<CardInSet> cardsInSet = cardEdition.getCardInSet(input.getName());
List<EditionEntry> cardsInSet = cardEdition.getCardInSet(input.getName());
if (cardsInSet.size() == 0) return false;
inputRarity = cardsInSet.get(0).rarity;
inputRarity = cardsInSet.get(0).rarity();
}
if (!rarity.isEmpty()) if (!inputRarity.toString().equals(rarity)) return false;
if (colorFilter.size() > 0)

View File

@@ -244,12 +244,12 @@ public class ConsoleCommandInterpreter {
if (s.length < 2) return "Command needs 2 parameters: Set code, collector number.";
CardEdition edition = StaticData.instance().getCardEdition(s[0]);
if (edition == null) return "Cannot find edition: " + s[0];
CardEdition.CardInSet cis = edition.getCardFromCollectorNumber(s[1]);
CardEdition.EditionEntry cis = edition.getCardFromCollectorNumber(s[1]);
if (cis == null) return String.format("Set '%s' does not have a card with collector number '%s'.", edition.getName(), s[1]);
PaperCard card = StaticData.instance().fetchCard(cis.name, edition.getCode(), cis.collectorNumber);
PaperCard card = StaticData.instance().fetchCard(cis.name(), edition.getCode(), cis.collectorNumber());
if(card == null) {
//Found in the set, not supported.
return String.format("Failed to fetch (%s, %s, %s) - Not currently supported.", cis.name, edition.getCode(), cis.collectorNumber);
return String.format("Failed to fetch (%s, %s, %s) - Not currently supported.", cis.name(), edition.getCode(), cis.collectorNumber());
}
if(s.length >= 3) {
try {

View File

@@ -25,7 +25,7 @@ import java.util.Set;
import forge.card.CardDb;
import forge.card.CardEdition;
import forge.card.CardEdition.CardInSet;
import forge.card.CardEdition.EditionEntry;
import forge.deck.generation.DeckGenPool;
import forge.game.GameType;
import forge.item.PaperCard;
@@ -192,9 +192,9 @@ public class ConquestPlane {
for (String setCode : setCodes) {
CardEdition edition = FModel.getMagicDb().getEditions().get(setCode);
if (edition != null) {
for (CardInSet card : edition.getAllCardsInSet()) {
if (bannedCardSet == null || !bannedCardSet.contains(card.name)) {
addCard(commonCards.getCard(card.name, setCode));
for (EditionEntry card : edition.getAllCardsInSet()) {
if (bannedCardSet == null || !bannedCardSet.contains(card.name())) {
addCard(commonCards.getCard(card.name(), setCode));
}
}
}

View File

@@ -28,7 +28,7 @@ import java.util.Map;
import java.util.Set;
import forge.card.CardEdition;
import forge.card.CardEdition.CardInSet;
import forge.card.CardEdition.EditionEntry;
import forge.card.CardRarity;
import forge.deck.Deck;
import forge.deck.DeckGroup;
@@ -445,9 +445,9 @@ public class QuestEventDraft implements IQuestEvent {
final List<String> cardNames = new ArrayList<>();
for (final CardEdition edition : getAllEditions()) {
for (final CardInSet card : edition.getAllCardsInSet()) {
if (card.rarity == CardRarity.Rare || card.rarity == CardRarity.MythicRare) {
final PaperCard cardToAdd = FModel.getMagicDb().getCommonCards().getCard(card.name, edition.getCode());
for (final EditionEntry card : edition.getAllCardsInSet()) {
if (card.rarity() == CardRarity.Rare || card.rarity() == CardRarity.MythicRare) {
final PaperCard cardToAdd = FModel.getMagicDb().getCommonCards().getCard(card.name(), edition.getCode());
if (cardToAdd != null && !cardNames.contains(cardToAdd.getName())) {
possibleCards.add(cardToAdd);
cardNames.add(cardToAdd.getName());
@@ -468,26 +468,26 @@ public class QuestEventDraft implements IQuestEvent {
private PaperCard getPromoCard() {
final CardEdition randomEdition = getRandomEdition();
final List<CardInSet> cardsInEdition = new ArrayList<>();
final List<EditionEntry> cardsInEdition = new ArrayList<>();
final List<String> cardNames = new ArrayList<>();
for (final CardInSet card : randomEdition.getAllCardsInSet()) {
if (card.rarity == CardRarity.Rare || card.rarity == CardRarity.MythicRare) {
if (!cardNames.contains(card.name)) {
for (final EditionEntry card : randomEdition.getAllCardsInSet()) {
if (card.rarity() == CardRarity.Rare || card.rarity() == CardRarity.MythicRare) {
if (!cardNames.contains(card.name())) {
cardsInEdition.add(card);
cardNames.add(card.name);
cardNames.add(card.name());
}
}
}
CardInSet randomCard;
EditionEntry randomCard;
PaperCard promo = null;
int attempts = 25;
while (promo == null && attempts-- > 0) {
randomCard = cardsInEdition.get((int) (MyRandom.getRandom().nextDouble() * cardsInEdition.size()));
promo = FModel.getMagicDb().getCommonCards().getCard(randomCard.name, randomEdition.getCode());
promo = FModel.getMagicDb().getCommonCards().getCard(randomCard.name(), randomEdition.getCode());
}
if (promo == null) {

View File

@@ -249,7 +249,7 @@ public abstract class ImageFetcher {
if (edition == null || edition.getType() == CardEdition.Type.CUSTOM_SET) return; //Custom set token, skip fetching.
//PaperToken pt = StaticData.instance().getAllTokens().getToken(tokenName, setCode);
Collection<CardEdition.TokenInSet> allTokens = edition.getTokens().get(tokenName);
Collection<CardEdition.EditionEntry> allTokens = edition.getTokens().get(tokenName);
if (!allTokens.isEmpty()) {
// This loop is going to try to download all the arts until it finds one
@@ -258,17 +258,17 @@ public abstract class ImageFetcher {
// Ideally we would have some mapping for generating card to determine which art indexed/collector number to try to fetch
// Token art we're downloading and which location we're storing it in.
// Once we're pulling from PaperTokens this section will change a bit
Iterator <CardEdition.TokenInSet> it = allTokens.iterator();
CardEdition.TokenInSet tis;
Iterator <CardEdition.EditionEntry> it = allTokens.iterator();
CardEdition.EditionEntry tis;
while(it.hasNext()) {
tis = it.next();
String tokenCode = edition.getTokensCode();
String langCode = edition.getCardsLangCode();
if (tis.collectorNumber == null || tis.collectorNumber.isEmpty()) {
if (tis.collectorNumber() == null || tis.collectorNumber().isEmpty()) {
continue;
}
downloadUrls.add(ForgeConstants.URL_PIC_SCRYFALL_DOWNLOAD + ImageUtil.getScryfallTokenDownloadUrl(tis.collectorNumber, tokenCode, langCode));
downloadUrls.add(ForgeConstants.URL_PIC_SCRYFALL_DOWNLOAD + ImageUtil.getScryfallTokenDownloadUrl(tis.collectorNumber(), tokenCode, langCode));
}
}