Generate individual booster slots with individual replacement percentages

Convert MH3 to booster slot percentages
This commit is contained in:
Chris H
2024-07-31 19:11:11 -04:00
parent 658542309a
commit 4554dee721
25 changed files with 520 additions and 348 deletions

View File

@@ -52,9 +52,9 @@ public class StaticData {
private boolean sourceImageForClone;
// Loaded lazily:
private IStorage<SealedProduct.Template> boosters;
private IStorage<SealedProduct.Template> specialBoosters;
private IStorage<SealedProduct.Template> tournaments;
private IStorage<SealedTemplate> boosters;
private IStorage<SealedTemplate> specialBoosters;
private IStorage<SealedTemplate> tournaments;
private IStorage<FatPack.Template> fatPacks;
private IStorage<BoosterBox.Template> boosterBoxes;
private IStorage<PrintSheet> printSheets;
@@ -362,23 +362,23 @@ public class StaticData {
return this.commonCards.contains(cr.cardName) || this.variantCards.contains(cr.cardName);
}
/** @return {@link forge.util.storage.IStorage}<{@link forge.item.SealedProduct.Template}> */
public final IStorage<SealedProduct.Template> getTournamentPacks() {
/** @return {@link forge.util.storage.IStorage}<{@link forge.item.SealedTemplate}> */
public final IStorage<SealedTemplate> getTournamentPacks() {
if (tournaments == null)
tournaments = new StorageBase<>("Starter sets", new SealedProduct.Template.Reader(new File(blockDataFolder, "starters.txt")));
tournaments = new StorageBase<>("Starter sets", new SealedTemplate.Reader(new File(blockDataFolder, "starters.txt")));
return tournaments;
}
/** @return {@link forge.util.storage.IStorage}<{@link forge.item.SealedProduct.Template}> */
public final IStorage<SealedProduct.Template> getBoosters() {
/** @return {@link forge.util.storage.IStorage}<{@link forge.item.SealedTemplate}> */
public final IStorage<SealedTemplate> getBoosters() {
if (boosters == null)
boosters = new StorageBase<>("Boosters", editions.getBoosterGenerator());
return boosters;
}
public final IStorage<SealedProduct.Template> getSpecialBoosters() {
public final IStorage<SealedTemplate> getSpecialBoosters() {
if (specialBoosters == null)
specialBoosters = new StorageBase<>("Special boosters", new SealedProduct.Template.Reader(new File(blockDataFolder, "boosters-special.txt")));
specialBoosters = new StorageBase<>("Special boosters", new SealedTemplate.Reader(new File(blockDataFolder, "boosters-special.txt")));
return specialBoosters;
}

View File

@@ -22,8 +22,10 @@ import com.google.common.collect.*;
import forge.StaticData;
import forge.card.CardDb.CardArtPreference;
import forge.deck.CardPool;
import forge.item.BoosterSlot;
import forge.item.PaperCard;
import forge.item.SealedProduct;
import forge.item.SealedTemplate;
import forge.item.SealedTemplateWithSlots;
import forge.util.*;
import forge.util.storage.StorageBase;
import forge.util.storage.StorageReaderBase;
@@ -276,6 +278,7 @@ public final class CardEdition implements Comparable<CardEdition> {
private String fatPackExtraSlots = "";
// Booster/draft info
private List<BoosterSlot> boosterSlots = null;
private boolean smallSetOverride = false;
private boolean foilAlwaysInCommonSlot = false;
private FoilType foilType = FoilType.NOT_SUPPORTED;
@@ -298,8 +301,8 @@ public final class CardEdition implements Comparable<CardEdition> {
private final Map<String, List<String>> customPrintSheetsToParse;
private int boosterArts = 1;
private SealedProduct.Template boosterTpl = null;
private final Map<String, SealedProduct.Template> boosterTemplates = new HashMap<>();
private SealedTemplate boosterTpl = null;
private final Map<String, SealedTemplate> boosterTemplates = new HashMap<>();
private CardEdition(ListMultimap<String, CardInSet> cardMap, Map<String, Integer> tokens, Map<String, List<String>> customPrintSheetsToParse) {
this.cardMap = cardMap;
@@ -471,10 +474,10 @@ public final class CardEdition implements Comparable<CardEdition> {
return boosterArts;
}
public SealedProduct.Template getBoosterTemplate() {
public SealedTemplate getBoosterTemplate() {
return getBoosterTemplate("Draft");
}
public SealedProduct.Template getBoosterTemplate(String boosterType) {
public SealedTemplate getBoosterTemplate(String boosterType) {
return boosterTemplates.get(boosterType);
}
public String getRandomBoosterKind() {
@@ -575,15 +578,23 @@ public final class CardEdition implements Comparable<CardEdition> {
);
ListMultimap<String, CardInSet> cardMap = ArrayListMultimap.create();
List<BoosterSlot> boosterSlots = Lists.newArrayList();
Map<String, Integer> tokenNormalized = new HashMap<>();
Map<String, List<String>> customPrintSheetsToParse = new HashMap<>();
List<String> editionSectionsWithCollectorNumbers = EditionSectionWithCollectorNumbers.getNames();
FileSection metadata = FileSection.parse(contents.get("metadata"), FileSection.EQUALS_KV_SEPARATOR);
List<String> boosterSlotsToParse = Lists.newArrayList();
if (metadata.contains("BoosterSlots")) {
boosterSlotsToParse = Lists.newArrayList(metadata.get("BoosterSlots").split(","));
}
for (String sectionName : contents.keySet()) {
// skip reserved section names like 'metadata' and 'tokens' that are handled separately
if (reservedSectionNames.contains(sectionName)) {
continue;
}
// parse sections of the format "<collector number> <rarity> <name>"
if (editionSectionsWithCollectorNumbers.contains(sectionName)) {
for(String line : contents.get(sectionName)) {
@@ -602,10 +613,12 @@ public final class CardEdition implements Comparable<CardEdition> {
cardMap.put(sectionName, cis);
}
}
// save custom print sheets of the format "<amount> <name>|<setcode>|<art index>"
// to parse later when printsheets are loaded lazily (and the cardpool is already initialized)
else {
} else if (boosterSlotsToParse.contains(sectionName)) {
// parse booster slots of the format "Base=N\n|Replace=<amount> <sheet>"
boosterSlots.add(BoosterSlot.parseSlot(sectionName, contents.get(sectionName)));
} else {
// save custom print sheets of the format "<amount> <name>|<setcode>|<art index>"
// to parse later when printsheets are loaded lazily (and the cardpool is already initialized)
customPrintSheetsToParse.put(sectionName, contents.get(sectionName));
}
}
@@ -625,31 +638,37 @@ public final class CardEdition implements Comparable<CardEdition> {
}
CardEdition res = new CardEdition(cardMap, tokenNormalized, customPrintSheetsToParse);
res.boosterSlots = boosterSlots;
// parse metadata section
FileSection section = FileSection.parse(contents.get("metadata"), FileSection.EQUALS_KV_SEPARATOR);
res.name = section.get("name");
res.date = parseDate(section.get("date"));
res.code = section.get("code");
res.code2 = section.get("code2");
res.name = metadata.get("name");
res.date = parseDate(metadata.get("date"));
res.code = metadata.get("code");
res.code2 = metadata.get("code2");
if (res.code2 == null) {
res.code2 = res.code;
}
res.scryfallCode = section.get("ScryfallCode");
res.scryfallCode = metadata.get("ScryfallCode");
if (res.scryfallCode == null) {
res.scryfallCode = res.code;
}
res.cardsLanguage = section.get("CardLang");
res.cardsLanguage = metadata.get("CardLang");
if (res.cardsLanguage == null) {
res.cardsLanguage = "en";
}
res.boosterArts = section.getInt("BoosterCovers", 1);
String boosterDesc = section.get("Booster");
res.boosterArts = metadata.getInt("BoosterCovers", 1);
if (section.contains("Booster")) {
String boosterDesc = metadata.get("Booster");
if (metadata.contains("Booster")) {
// Historical naming convention in Forge for "DraftBooster"
res.boosterTpl = new SealedProduct.Template(res.code, SealedProduct.Template.Reader.parseSlots(boosterDesc));
// Do i have access to editions slots?
if (res.boosterSlots != null) {
res.boosterTpl = new SealedTemplateWithSlots(res.code, SealedTemplate.Reader.parseSlots(boosterDesc), res.boosterSlots);
} else {
res.boosterTpl = new SealedTemplate(res.code, SealedTemplate.Reader.parseSlots(boosterDesc));
}
res.boosterTemplates.put("Draft", res.boosterTpl);
}
@@ -657,18 +676,18 @@ public final class CardEdition implements Comparable<CardEdition> {
// Theme boosters aren't here because they are closer to preconstructed decks, and should be treated as such
for (String type : boostertype) {
String name = type + "Booster";
if (section.contains(name)) {
res.boosterTemplates.put(type, new SealedProduct.Template(res.code, SealedProduct.Template.Reader.parseSlots(section.get(name))));
if (metadata.contains(name)) {
res.boosterTemplates.put(type, new SealedTemplate(res.code, SealedTemplate.Reader.parseSlots(metadata.get(name))));
}
}
res.alias = section.get("alias");
res.borderColor = BorderColor.valueOf(section.get("border", "Black").toUpperCase(Locale.ENGLISH));
res.alias = metadata.get("alias");
res.borderColor = BorderColor.valueOf(metadata.get("border", "Black").toUpperCase(Locale.ENGLISH));
Type enumType = Type.UNKNOWN;
if (this.isCustomEditions){
enumType = Type.CUSTOM_SET; // Forcing ThirdParty Edition Type to avoid inconsistencies
} else {
String type = section.get("type");
String type = metadata.get("type");
if (null != type && !type.isEmpty()) {
try {
enumType = Type.valueOf(type.toUpperCase(Locale.ENGLISH));
@@ -680,12 +699,12 @@ public final class CardEdition implements Comparable<CardEdition> {
}
res.type = enumType;
res.prerelease = section.get("Prerelease", null);
res.boosterBoxCount = Integer.parseInt(section.get("BoosterBox", enumType.getBoosterBoxDefault()));
res.fatPackCount = Integer.parseInt(section.get("FatPack", enumType.getFatPackDefault()));
res.fatPackExtraSlots = section.get("FatPackExtraSlots", "");
res.prerelease = metadata.get("Prerelease", null);
res.boosterBoxCount = Integer.parseInt(metadata.get("BoosterBox", enumType.getBoosterBoxDefault()));
res.fatPackCount = Integer.parseInt(metadata.get("FatPack", enumType.getFatPackDefault()));
res.fatPackExtraSlots = metadata.get("FatPackExtraSlots", "");
switch (section.get("foil", "newstyle").toLowerCase()) {
switch (metadata.get("foil", "newstyle").toLowerCase()) {
case "notsupported":
res.foilType = FoilType.NOT_SUPPORTED;
break;
@@ -701,25 +720,25 @@ public final class CardEdition implements Comparable<CardEdition> {
res.foilType = FoilType.NOT_SUPPORTED;
break;
}
String[] replaceCommon = section.get("ChanceReplaceCommonWith", "0F Common").split(" ", 2);
String[] replaceCommon = metadata.get("ChanceReplaceCommonWith", "0F Common").split(" ", 2);
res.chanceReplaceCommonWith = Double.parseDouble(replaceCommon[0]);
res.slotReplaceCommonWith = replaceCommon[1];
res.foilChanceInBooster = section.getDouble("FoilChanceInBooster", 21.43F) / 100.0F;
res.foilChanceInBooster = metadata.getDouble("FoilChanceInBooster", 21.43F) / 100.0F;
res.foilAlwaysInCommonSlot = section.getBoolean("FoilAlwaysInCommonSlot", true);
res.additionalSheetForFoils = section.get("AdditionalSheetForFoils", "");
res.foilAlwaysInCommonSlot = metadata.getBoolean("FoilAlwaysInCommonSlot", true);
res.additionalSheetForFoils = metadata.get("AdditionalSheetForFoils", "");
res.additionalUnlockSet = section.get("AdditionalSetUnlockedInQuest", ""); // e.g. Time Spiral Timeshifted (TSB) for Time Spiral
res.additionalUnlockSet = metadata.get("AdditionalSetUnlockedInQuest", ""); // e.g. Time Spiral Timeshifted (TSB) for Time Spiral
res.smallSetOverride = section.getBoolean("TreatAsSmallSet", false); // for "small" sets with over 200 cards (e.g. Eldritch Moon)
res.doublePickDuringDraft = section.get("DoublePick", ""); // "FirstPick" or "Always"
res.smallSetOverride = metadata.getBoolean("TreatAsSmallSet", false); // for "small" sets with over 200 cards (e.g. Eldritch Moon)
res.doublePickDuringDraft = metadata.get("DoublePick", ""); // "FirstPick" or "Always"
res.boosterMustContain = section.get("BoosterMustContain", ""); // e.g. Dominaria guaranteed legendary creature
res.boosterReplaceSlotFromPrintSheet = section.get("BoosterReplaceSlotFromPrintSheet", ""); // e.g. Zendikar Rising guaranteed double-faced card
res.sheetReplaceCardFromSheet = section.get("SheetReplaceCardFromSheet", "");
res.sheetReplaceCardFromSheet2 = section.get("SheetReplaceCardFromSheet2", "");
res.chaosDraftThemes = section.get("ChaosDraftThemes", "").split(";"); // semicolon separated list of theme names
res.boosterMustContain = metadata.get("BoosterMustContain", ""); // e.g. Dominaria guaranteed legendary creature
res.boosterReplaceSlotFromPrintSheet = metadata.get("BoosterReplaceSlotFromPrintSheet", ""); // e.g. Zendikar Rising guaranteed double-faced card
res.sheetReplaceCardFromSheet = metadata.get("SheetReplaceCardFromSheet", "");
res.sheetReplaceCardFromSheet2 = metadata.get("SheetReplaceCardFromSheet2", "");
res.chaosDraftThemes = metadata.get("ChaosDraftThemes", "").split(";"); // semicolon separated list of theme names
return res;
}
@@ -806,11 +825,11 @@ public final class CardEdition implements Comparable<CardEdition> {
public final Comparator<PaperCard> CARD_EDITION_COMPARATOR = Comparator.comparing(c -> Collection.this.get(c.getEdition()));
public IItemReader<SealedProduct.Template> getBoosterGenerator() {
return new StorageReaderBase<SealedProduct.Template>(null) {
public IItemReader<SealedTemplate> getBoosterGenerator() {
return new StorageReaderBase<SealedTemplate>(null) {
@Override
public Map<String, SealedProduct.Template> readAll() {
Map<String, SealedProduct.Template> map = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
public Map<String, SealedTemplate> readAll() {
Map<String, SealedTemplate> map = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
for (CardEdition ce : Collection.this) {
List<String> boosterTypes = Lists.newArrayList(ce.getAvailableBoosterTypes());
for (String type : boosterTypes) {
@@ -823,7 +842,7 @@ public final class CardEdition implements Comparable<CardEdition> {
}
@Override
public String getItemKey(SealedProduct.Template item) {
public String getItemKey(SealedTemplate item) {
return item.getEdition();
}

View File

@@ -18,6 +18,7 @@
package forge.item;
import com.google.common.base.Function;
import java.util.ArrayList;
import org.apache.commons.lang3.tuple.Pair;
@@ -63,7 +64,7 @@ public class BoosterBox extends BoxedProduct {
return super.getTotalCards() * fpData.getCntBoosters() + fpData.getNumberOfCardsExpected();
}
public static class Template extends SealedProduct.Template {
public static class Template extends SealedTemplate {
private final int cntBoosters;
public int getCntBoosters() { return cntBoosters; }

View File

@@ -18,7 +18,7 @@
package forge.item;
import org.apache.commons.lang3.tuple.Pair;
import com.google.common.base.Function;
import com.google.common.collect.ImmutableList;
@@ -27,6 +27,7 @@ import forge.StaticData;
import forge.card.CardEdition;
import forge.item.generation.BoosterSlots;
import forge.util.MyRandom;
import org.apache.commons.lang3.tuple.Pair;
public class BoosterPack extends SealedProduct {
private final int artIndex;
@@ -34,14 +35,14 @@ public class BoosterPack extends SealedProduct {
public static BoosterPack fromSet(CardEdition edition) {
String boosterKind = edition.getRandomBoosterKind();
Template d = edition.getBoosterTemplate(boosterKind);
SealedTemplate d = edition.getBoosterTemplate(boosterKind);
StringBuilder sb = new StringBuilder(edition.getName());
sb.append(" ").append(boosterKind);
return new BoosterPack(sb.toString(), d);
}
public static BoosterPack fromColor(final String color) {
return new BoosterPack(color, new Template("?", ImmutableList.of(
return new BoosterPack(color, new SealedTemplate("?", ImmutableList.of(
Pair.of(BoosterSlots.COMMON + ":color(\"" + color + "\"):!" + BoosterSlots.LAND, 11),
Pair.of(BoosterSlots.UNCOMMON + ":color(\"" + color + "\"):!" + BoosterSlots.LAND, 3),
Pair.of(BoosterSlots.RARE_MYTHIC + ":color(\"" + color + "\"):!" + BoosterSlots.LAND, 1),
@@ -49,7 +50,7 @@ public class BoosterPack extends SealedProduct {
));
}
public BoosterPack(final String name0, final Template boosterData) {
public BoosterPack(final String name0, final SealedTemplate boosterData) {
super(name0, boosterData);
if (specialSets.contains(boosterData.getEdition()) || boosterData.getEdition().equals("?")) {
@@ -86,7 +87,7 @@ public class BoosterPack extends SealedProduct {
return new BoosterPack(name, contents);
}
public Template getBoosterData() {
public SealedTemplate getBoosterData() {
return contents;
}

View File

@@ -0,0 +1,72 @@
package forge.item;
import com.google.common.collect.Lists;
import java.util.List;
import java.util.TreeMap;
public class BoosterSlot {
private final String slotName;
private String baseRarity;
private float startRange = 0.0f;
private final TreeMap<Float, String> slotPercentages = new TreeMap<>();
public BoosterSlot(final String slotName, final List<String> contents) {
this.slotName = slotName;
this.baseRarity = null;
parseContents(contents);
}
public final String getSlotName() {
return slotName;
}
public static BoosterSlot parseSlot(final String slotName, final List<String> contents) {
return new BoosterSlot(slotName, contents);
}
private void parseContents(List<String> contents) {
for (String content : contents) {
if (content.startsWith("#")) {
continue;
}
String[] parts = content.split("=", 2);
String key = parts[0];
String value = parts[1];
if (key.equalsIgnoreCase("Base")) {
baseRarity = value;
} else if (key.equalsIgnoreCase("Replace")) {
// Are there other things?
String[] replaceParts = value.split(" ", 2);
float pct = Float.parseFloat(replaceParts[0]);
startRange += pct;
slotPercentages.put(startRange, replaceParts[1]);
}
}
}
public List<String> getSlotSheet(int amount) {
// For the first item in the slot, run float percentages
List<String> sheets = Lists.newArrayList();
sheets.add(replaceSlot());
for(int i = 1; i < amount; i++) {
sheets.add(baseRarity);
}
return sheets;
}
public String replaceSlot() {
double rand = Math.random() * 100;
for (Float key : slotPercentages.keySet()) {
if (rand < key) {
System.out.println("Replaced a base slot! " + slotName + " -> " + slotPercentages.get(key));
return slotPercentages.get(key);
}
}
// If we didn't find a key, return the base rarity from that edition
return baseRarity;
}
}

View File

@@ -10,7 +10,7 @@ public abstract class BoxedProduct extends SealedProduct {
private int numberOfPacks;
public BoxedProduct(String name0, Template boosterData, int numberOfPacks) {
public BoxedProduct(String name0, SealedTemplate boosterData, int numberOfPacks) {
super(name0, boosterData);
this.numberOfPacks = numberOfPacks;
}

View File

@@ -18,14 +18,14 @@
package forge.item;
import java.util.List;
import org.apache.commons.lang3.tuple.Pair;
import com.google.common.base.Function;
import forge.ImageKeys;
import forge.StaticData;
import forge.card.CardEdition;
import forge.item.generation.BoosterGenerator;
import org.apache.commons.lang3.tuple.Pair;
import java.util.List;
public class FatPack extends BoxedProduct {
public static FatPack fromSet(final CardEdition edition) {
@@ -72,7 +72,7 @@ public class FatPack extends BoxedProduct {
return super.getTotalCards() * fpData.getCntBoosters() + fpData.getNumberOfCardsExpected();
}
public static class Template extends SealedProduct.Template {
public static class Template extends SealedTemplate {
private final int cntBoosters;
public int getCntBoosters() { return cntBoosters; }

View File

@@ -18,32 +18,22 @@
package forge.item;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import org.apache.commons.lang3.tuple.ImmutablePair;
import org.apache.commons.lang3.tuple.Pair;
import com.google.common.base.Function;
import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import forge.StaticData;
import forge.card.CardRulesPredicates;
import forge.item.generation.BoosterGenerator;
import forge.item.generation.BoosterSlots;
import forge.util.Aggregates;
import forge.util.TextUtil;
import forge.util.storage.StorageReaderFile;
import java.util.ArrayList;
import java.util.List;
public abstract class SealedProduct implements InventoryItemFromSet {
public static final List<String> specialSets = new ArrayList<>();
protected final Template contents;
protected final SealedTemplate contents;
protected final String name;
private final int hash;
protected List<PaperCard> cards = null;
@@ -57,7 +47,7 @@ public abstract class SealedProduct implements InventoryItemFromSet {
specialSets.add("Colorless");
}
public SealedProduct(String name0, Template boosterData) {
public SealedProduct(String name0, SealedTemplate boosterData) {
if (null == name0) { throw new IllegalArgumentException("name0 must not be null"); }
if (null == boosterData) {
throw new IllegalArgumentException("boosterData for " + name0 + " must not be null");
@@ -115,6 +105,7 @@ public abstract class SealedProduct implements InventoryItemFromSet {
protected List<PaperCard> generate() {
return BoosterGenerator.getBoosterPack(contents);
}
protected PaperCard getRandomBasicLand(final String setCode) {
@@ -127,124 +118,4 @@ public abstract class SealedProduct implements InventoryItemFromSet {
Predicates.compose(CardRulesPredicates.Presets.IS_BASIC_LAND, PaperCard::getRules));
return Aggregates.random(Iterables.filter(StaticData.instance().getCommonCards().getAllCards(), cardsRule), count);
}
public static class Template {
@SuppressWarnings("unchecked")
public final static Template genericDraftBooster = new Template(null, Lists.newArrayList(
Pair.of(BoosterSlots.COMMON, 10), Pair.of(BoosterSlots.UNCOMMON, 3),
Pair.of(BoosterSlots.RARE_MYTHIC, 1), Pair.of(BoosterSlots.BASIC_LAND, 1)
));
protected final List<Pair<String, Integer>> slots;
protected final String name;
public final List<Pair<String, Integer>> getSlots() {
return slots;
}
public final String getName() {
return name;
}
public boolean hasSlot(String s)
{
for (Pair<String, Integer> slot : getSlots()) {
String slotName = slot.getLeft();
// Anything after a space or ! or : is not part of the slot's main type
if (slotName.split("[ :!]")[0].equals(s)) {
return true;
}
}
return false;
}
public final String getEdition() {
return name;
}
public Template(Iterable<Pair<String, Integer>> itrSlots)
{
this(null, itrSlots);
}
public Template(String name0, Iterable<Pair<String, Integer>> itrSlots)
{
slots = Lists.newArrayList(itrSlots);
name = name0;
}
public Template(String code, String boosterDesc) {
this(code, Reader.parseSlots(boosterDesc));
}
public int getNumberOfCardsExpected() {
int sum = 0;
for(Pair<String, Integer> p : slots) {
sum += p.getRight();
}
return sum;
}
@Override
public String toString() {
StringBuilder s = new StringBuilder();
s.append("consisting of ");
for(Pair<String, Integer> p : slots) {
s.append(p.getRight()).append(" ").append(p.getLeft()).append(", ");
}
// trim the last comma and space
s.replace(s.length() - 2, s.length(), "");
// put an 'and' before the previous comma
int lastCommaIdx = s.lastIndexOf(",");
if (0 < lastCommaIdx) {
s.replace(lastCommaIdx+1, lastCommaIdx+1, " and");
}
return s.toString();
}
@Override
public boolean equals(final Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Template template = (Template) o;
return slots.equals(template.slots) && name.equals(template.name);
}
@Override
public int hashCode() {
int result = slots.hashCode();
result = 31 * result + name.hashCode();
return result;
}
public final static class Reader extends StorageReaderFile<Template> {
public Reader(File file) {
super(file, (Function<? super Template, String>) (Function<Template, String>) Template::getName);
}
public static List<Pair<String, Integer>> parseSlots(String data) {
final String[] dataz = TextUtil.splitWithParenthesis(data, ',');
List<Pair<String, Integer>> slots = new ArrayList<>();
for (String slotDesc : dataz) {
String[] kv = TextUtil.splitWithParenthesis(slotDesc, ' ', 2);
slots.add(ImmutablePair.of(kv[1].replace(";", ","), Integer.parseInt(kv[0])));
}
return slots;
}
@Override
protected Template read(String line, int i) {
String[] headAndData = TextUtil.split(line, ':', 2);
return new Template(headAndData[0], parseSlots(headAndData[1]));
}
}
}
}

View File

@@ -0,0 +1,132 @@
package forge.item;
import com.google.common.base.Function;
import com.google.common.collect.Lists;
import forge.item.generation.BoosterSlots;
import forge.util.TextUtil;
import forge.util.storage.StorageReaderFile;
import org.apache.commons.lang3.tuple.ImmutablePair;
import org.apache.commons.lang3.tuple.Pair;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
public class SealedTemplate {
@SuppressWarnings("unchecked")
public final static SealedTemplate genericDraftBooster = new SealedTemplate(null, Lists.newArrayList(
Pair.of(BoosterSlots.COMMON, 10), Pair.of(BoosterSlots.UNCOMMON, 3),
Pair.of(BoosterSlots.RARE_MYTHIC, 1), Pair.of(BoosterSlots.BASIC_LAND, 1)
));
protected final List<Pair<String, Integer>> slots;
protected final String name;
public final List<Pair<String, Integer>> getSlots() {
return slots;
}
public boolean hasSlot(String s) {
for (Pair<String, Integer> slot : getSlots()) {
String slotName = slot.getLeft();
// Anything after a space or ! or : is not part of the slot's main type
if (slotName.split("[ :!]")[0].equals(s)) {
return true;
}
}
return false;
}
public final String getEdition() {
return name;
}
public SealedTemplate(Iterable<Pair<String, Integer>> itrSlots) {
this(null, itrSlots);
}
public SealedTemplate(String name0, Iterable<Pair<String, Integer>> itrSlots) {
slots = Lists.newArrayList(itrSlots);
name = name0;
}
public SealedTemplate(String code, String boosterDesc) {
this(code, Reader.parseSlots(boosterDesc));
}
public int getNumberOfCardsExpected() {
int sum = 0;
for(Pair<String, Integer> p : slots) {
sum += p.getRight();
}
return sum;
}
public static final Function<? super SealedTemplate, String> FN_GET_NAME = new Function<SealedTemplate, String>() {
@Override
public String apply(SealedTemplate arg1) {
return arg1.name;
}
};
@Override
public String toString() {
StringBuilder s = new StringBuilder();
s.append("consisting of ");
for(Pair<String, Integer> p : slots) {
s.append(p.getRight()).append(" ").append(p.getLeft()).append(", ");
}
// trim the last comma and space
s.replace(s.length() - 2, s.length(), "");
// put an 'and' before the previous comma
int lastCommaIdx = s.lastIndexOf(",");
if (0 < lastCommaIdx) {
s.replace(lastCommaIdx+1, lastCommaIdx+1, " and");
}
return s.toString();
}
@Override
public boolean equals(final Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
SealedTemplate template = (SealedTemplate) o;
return slots.equals(template.slots) && name.equals(template.name);
}
@Override
public int hashCode() {
int result = slots.hashCode();
result = 31 * result + name.hashCode();
return result;
}
public final static class Reader extends StorageReaderFile<SealedTemplate> {
public Reader(File file) {
super(file, SealedTemplate.FN_GET_NAME);
}
public static List<Pair<String, Integer>> parseSlots(String data) {
final String[] dataz = TextUtil.splitWithParenthesis(data, ',');
List<Pair<String, Integer>> slots = new ArrayList<>();
for (String slotDesc : dataz) {
String[] kv = TextUtil.splitWithParenthesis(slotDesc, ' ', 2);
slots.add(ImmutablePair.of(kv[1].replace(";", ","), Integer.parseInt(kv[0])));
}
return slots;
}
@Override
protected SealedTemplate read(String line, int i) {
String[] headAndData = TextUtil.split(line, ':', 2);
return new SealedTemplate(headAndData[0], parseSlots(headAndData[1]));
}
}
}

View File

@@ -0,0 +1,21 @@
package forge.item;
import org.apache.commons.lang3.tuple.Pair;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;
public class SealedTemplateWithSlots extends SealedTemplate {
private final List<BoosterSlot> boosterSlots;
public SealedTemplateWithSlots(String name0, Iterable<Pair<String, Integer>> itrSlots, List<BoosterSlot> boosterSlots) {
super(name0, itrSlots);
this.boosterSlots = boosterSlots;
}
public Map<String, BoosterSlot> getNamedSlots() {
return boosterSlots.stream().collect(Collectors.toMap(BoosterSlot::getSlotName, Function.identity()));
}
}

View File

@@ -17,6 +17,7 @@
*/
package forge.item;
import com.google.common.base.Function;
import java.util.List;
import forge.ImageKeys;
@@ -24,14 +25,16 @@ import forge.StaticData;
import forge.card.CardEdition;
import forge.item.generation.BoosterGenerator;
import java.util.List;
public class TournamentPack extends SealedProduct {
public static TournamentPack fromSet(CardEdition edition) {
Template d = StaticData.instance().getTournamentPacks().get(edition.getCode());
SealedTemplate d = StaticData.instance().getTournamentPacks().get(edition.getCode());
return new TournamentPack(edition.getName(), d);
}
public TournamentPack(final String name0, final Template boosterData) {
public TournamentPack(final String name0, final SealedTemplate boosterData) {
super(name0, boosterData);
}

View File

@@ -17,39 +17,23 @@
*/
package forge.item.generation;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.Pair;
import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import forge.StaticData;
import forge.card.CardEdition;
import forge.card.*;
import forge.card.CardEdition.FoilType;
import forge.card.CardRarity;
import forge.card.CardRulesPredicates;
import forge.card.CardSplitType;
import forge.card.PrintSheet;
import forge.item.IPaperCard;
import forge.item.*;
import forge.item.IPaperCard.Predicates.Presets;
import forge.item.PaperCard;
import forge.item.SealedProduct;
import forge.util.Aggregates;
import forge.util.MyRandom;
import forge.util.TextUtil;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.Pair;
import java.util.*;
/**
* <p>
@@ -79,7 +63,7 @@ public class BoosterGenerator {
return randomCard.getFoiled();
}
public static List<PaperCard> getBoosterPack(SealedProduct.Template template) {
public static List<PaperCard> getBoosterPack(SealedTemplate template) {
// TODO: tweak the chances of generating Masterpieces to be more authentic
// (currently merely added to the Rare/Mythic Rare print sheet via ExtraFoilSheetKey)
@@ -407,7 +391,56 @@ public class BoosterGenerator {
return result;
}
private static void ensureGuaranteedCardInBooster(List<PaperCard> result, SealedProduct.Template template, String boosterMustContain) {
public static List<PaperCard> getBoosterPack(SealedTemplateWithSlots template) {
// SealedTemplateWithSlots ignores all Edition level params
// Instead each slot defines their percentages on their own
CardEdition edition = StaticData.instance().getEditions().get(template.getEdition());
List<PaperCard> result = new ArrayList<>();
Map<String, BoosterSlot> boosterSlots = template.getNamedSlots();
for (Pair<String, Integer> slot : template.getSlots()) {
String slotType = slot.getLeft().trim();
int numCards = slot.getRight();
System.out.println(numCards + " of type " + slotType);
// For cards that end in '+', attempt to convert this card to foil.
boolean convertCardFoil = slotType.endsWith("+");
if (convertCardFoil) {
slotType = slotType.substring(0, slotType.length() - 1);
}
// Unpack Base
BoosterSlot boosterSlot = boosterSlots.get(slotType);
String determineSheet = boosterSlot.replaceSlot();
String setCode = template.getEdition();
// Ok, so we have a sheet now. Most should be standard sheets, but some named edition sheets
List<PaperCard> paperCards;
PrintSheet ps;
try {
// Apply the edition to the sheet name by default. We'll try again if thats not a real sheet
ps = getPrintSheet(determineSheet + " " + setCode);
} catch(Exception e) {
ps = getPrintSheet(determineSheet);
}
if (convertCardFoil) {
paperCards = Lists.newArrayList();
for(PaperCard pc : ps.random(numCards, true)) {
paperCards.add(pc.getFoiled());
}
} else {
paperCards = ps.random(numCards, true);
}
result.addAll(paperCards);
}
return result;
}
private static void ensureGuaranteedCardInBooster(List<PaperCard> result, SealedTemplate template, String boosterMustContain) {
// First, see if there's already a card of the given type
String[] types = TextUtil.split(boosterMustContain, ' ');
boolean alreadyHaveCard = false;

View File

@@ -1,25 +1,24 @@
package forge.item.generation;
import com.google.common.base.Predicate;
import com.google.common.collect.Iterables;
import forge.StaticData;
import forge.card.PrintSheet;
import forge.item.PaperCard;
import forge.item.SealedTemplate;
import forge.item.SealedTemplateWithSlots;
import forge.util.ItemPool;
import org.apache.commons.lang3.tuple.Pair;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import org.apache.commons.lang3.tuple.Pair;
import com.google.common.base.Predicate;
import com.google.common.collect.Iterables;
import forge.StaticData;
import forge.card.PrintSheet;
import forge.item.PaperCard;
import forge.item.SealedProduct;
import forge.util.ItemPool;
public class UnOpenedProduct implements IUnOpenedProduct {
private final SealedProduct.Template tpl;
private final SealedTemplate tpl;
private final Map<String, PrintSheet> sheets;
private boolean poolLimited = false; // if true after successful generation cards are removed from printsheets.
@@ -32,23 +31,23 @@ public class UnOpenedProduct implements IUnOpenedProduct {
}
// Means to select from all unique cards (from base game, ie. no schemes or avatars)
public UnOpenedProduct(SealedProduct.Template template) {
public UnOpenedProduct(SealedTemplate template) {
tpl = template;
sheets = null;
}
// Invoke this constructor only if you are sure that the pool is not equal to deafult carddb
public UnOpenedProduct(SealedProduct.Template template, ItemPool<PaperCard> pool) {
public UnOpenedProduct(SealedTemplate template, ItemPool<PaperCard> pool) {
this(template, pool.toFlatList());
}
public UnOpenedProduct(SealedProduct.Template template, Iterable<PaperCard> cards) {
public UnOpenedProduct(SealedTemplate template, Iterable<PaperCard> cards) {
tpl = template;
sheets = new TreeMap<>();
prebuildSheets(cards);
}
public UnOpenedProduct(SealedProduct.Template sealedProductTemplate, Predicate<PaperCard> filterPrinted) {
public UnOpenedProduct(SealedTemplate sealedProductTemplate, Predicate<PaperCard> filterPrinted) {
this(sealedProductTemplate, Iterables.filter(StaticData.instance().getCommonCards().getAllCards(), filterPrinted));
}
@@ -60,7 +59,13 @@ public class UnOpenedProduct implements IUnOpenedProduct {
@Override
public List<PaperCard> get() {
return sheets == null ? BoosterGenerator.getBoosterPack(tpl) : getBoosterPack();
if (sheets != null) {
return getBoosterPack();
} else if (tpl instanceof SealedTemplateWithSlots) {
return BoosterGenerator.getBoosterPack((SealedTemplateWithSlots) tpl);
}
return BoosterGenerator.getBoosterPack(tpl);
}
// If they request cards from an arbitrary pool, there's no use to cache printsheets.

View File

@@ -1,10 +1,5 @@
package forge.game.ability.effects;
import java.util.List;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Map;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import forge.StaticData;
@@ -23,11 +18,16 @@ import forge.game.zone.ZoneType;
import forge.item.BoosterPack;
import forge.item.IPaperCard;
import forge.item.PaperCard;
import forge.item.SealedProduct;
import forge.item.SealedTemplate;
import forge.util.Aggregates;
import forge.util.CardTranslation;
import forge.util.Localizer;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
public class MakeCardEffect extends SpellAbilityEffect {
@Override
public void resolve(SpellAbility sa) {
@@ -83,7 +83,7 @@ public class MakeCardEffect extends SpellAbilityEffect {
} else if (sa.hasParam("Choices")) {
faces.addAll(parseFaces(sa, "Choices"));
} else if (sa.hasParam("Booster")) {
SealedProduct.Template booster = Aggregates.random(StaticData.instance().getBoosters());
SealedTemplate booster = Aggregates.random(StaticData.instance().getBoosters());
pack = new BoosterPack(booster.getEdition(), booster).getCards();
for (PaperCard pc : pack) {
ICardFace face = pc.getRules().getMainPart();

View File

@@ -9,7 +9,7 @@ import forge.gamemodes.limited.IBoosterDraft;
import forge.gamemodes.limited.IDraftLog;
import forge.gamemodes.limited.LimitedPlayer;
import forge.item.PaperCard;
import forge.item.SealedProduct;
import forge.item.SealedTemplate;
import forge.item.generation.BoosterGenerator;
import forge.model.FModel;
import org.testng.annotations.Test;
@@ -54,7 +54,7 @@ public class BoosterDraftTest implements IBoosterDraft {
@Override
public CardPool nextChoice() {
this.n--;
SealedProduct.Template booster = FModel.getMagicDb().getBoosters().get("M11");
SealedTemplate booster = FModel.getMagicDb().getBoosters().get("M11");
CardPool result = new CardPool();
result.addAllFlat(BoosterGenerator.getBoosterPack(booster));
return result;

View File

@@ -7,7 +7,7 @@ import forge.adventure.player.AdventurePlayer;
import forge.adventure.pointofintrest.PointOfInterestChanges;
import forge.deck.Deck;
import forge.item.PaperCard;
import forge.item.SealedProduct;
import forge.item.SealedTemplate;
import forge.item.generation.BoosterGenerator;
import forge.item.generation.UnOpenedProduct;
import forge.model.CardBlock;
@@ -145,7 +145,7 @@ public class AdventureEventController implements Serializable {
//Get all candidates then remove at random until no more than count are included
//This will prevent duplicate choices within a round of a Jumpstart draft
List<Deck> packsAsDecks = new ArrayList<>();
for(SealedProduct.Template template : StaticData.instance().getSpecialBoosters())
for(SealedTemplate template : StaticData.instance().getSpecialBoosters())
{
if (!template.getEdition().contains(block.getLandSet().getCode()))
continue;

View File

@@ -19,7 +19,7 @@ import forge.deck.io.DeckSerializer;
import forge.game.GameFormat;
import forge.item.BoosterPack;
import forge.item.PaperCard;
import forge.item.SealedProduct;
import forge.item.SealedTemplate;
import forge.item.generation.UnOpenedProduct;
import forge.model.FModel;
import forge.util.Aggregates;
@@ -436,7 +436,7 @@ public class CardUtil {
}
packCandidates=new HashMap<>();
for(SealedProduct.Template template : StaticData.instance().getSpecialBoosters())
for(SealedTemplate template : StaticData.instance().getSpecialBoosters())
{
if (!editionCodes.contains(template.getEdition().split("\\s",2)[0]))
continue;

View File

@@ -3,14 +3,51 @@ Code=MH3
Date=2024-06-07
Name=Modern Horizons 3
Type=Draft
Booster=6 Common, 3 Uncommon, 1 RareMythic, 1 fromSheet("MH3 new to modern"), 1 Land, 1 Any, 1 Any+
# This isn't the right ratios yet. But it's a start
ChanceReplaceCommonWith=.0156F fromsheet("MH3 special guests")
BoosterSlots=Common,Common-Guest,Uncommon,RareMythic,NewToModern,Common-Land,Wildcard
Booster=5 Common, 1 Common-Guest, 3 Uncommon, 1 RareMythic, 1 NewToModern, 1 Common-Land, 1 Wildcard, 1 Wildcard+
BoosterBox=36
BoosterCovers=3
ChaosDraftThemes=MASTERS_SET
ScryfallCode=MH3
[Common]
Base=Common
[Common-Guest]
Base=Common
Replace=.015625F fromSheet("MH3 special guests")
[Uncommon]
Base=Uncommon
[RareMythic]
Base=RareMythic
Replace=.021F fromSheet("MH3 retro frame")
# Fetch lands, Concept Eldrazi, Planeswalkers, Frame Break treatments, Profile treatments, and borderless treatments on Rare or Mythic Rare cards will appear 5.1 percent of the time
Replace=.051F fromSheet("MH3 booster fun")
[Common-Land]
Base=Common
Replace=.20F Land
Replace=.133F Land+
Replace=.10F fromSheet("MH3 full art")
Replace=.067F fromSheet("MH3 full art")+
[NewToModern]
Base=Uncommon:fromSheet("MH3 new to modern")
Replace=.213F Rare:fromSheet("MH3 new to modern")
Replace=.023F Mythic:fromSheet("MH3 new to modern")
Replace=.008F fromSheet("MH3 borderless frame")
Replace=.003F fromSheet("MH3 borderless profile")
Replace=.001F fromSheet("MH3 retro")
[Wildcard]
Base=Common
Replace=.417F Uncommon
Replace=.078F MythicRare
Replace=.004F fromSheet("MH3 borderless frame")
Replace=.042F fromSheet("MH3 retro")
[cards]
1 U Breaker of Creation @Yohann Schepacz
2 R Devourer of Destiny @Raph Lomotan

View File

@@ -28,7 +28,7 @@ import forge.deck.DeckBase;
import forge.gui.util.SGuiChoose;
import forge.gui.util.SOptionPane;
import forge.item.PaperCard;
import forge.item.SealedProduct;
import forge.item.SealedTemplate;
import forge.item.generation.ChaosBoosterSupplier;
import forge.item.generation.IUnOpenedProduct;
import forge.item.generation.UnOpenedProduct;
@@ -85,7 +85,7 @@ public class BoosterDraft implements IBoosterDraft {
protected boolean generateProduct() {
switch (this.draftFormat) {
case Full: // Draft from all cards in Forge
final Supplier<List<PaperCard>> s = new UnOpenedProduct(SealedProduct.Template.genericDraftBooster);
final Supplier<List<PaperCard>> s = new UnOpenedProduct(SealedTemplate.genericDraftBooster);
for (int i = 0; i < 3; i++) {
this.product.add(s);
@@ -303,7 +303,7 @@ public class BoosterDraft implements IBoosterDraft {
throw new RuntimeException("BoosterGenerator : deck not found");
}
final SealedProduct.Template tpl = draft.getSealedProductTemplate();
final SealedTemplate tpl = draft.getSealedProductTemplate();
final UnOpenedProduct toAdd = new UnOpenedProduct(tpl, dPool);
toAdd.setLimitedPool(draft.isSingleton());

View File

@@ -17,23 +17,22 @@
*/
package forge.gamemodes.limited;
import java.util.ArrayList;
import java.util.List;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.ImmutablePair;
import org.apache.commons.lang3.tuple.Pair;
import forge.card.CardEdition;
import forge.deck.Deck;
import forge.deck.DeckBase;
import forge.item.PaperCard;
import forge.item.SealedProduct;
import forge.item.SealedTemplate;
import forge.model.FModel;
import forge.util.FileSection;
import forge.util.ItemPool;
import forge.util.TextUtil;
import forge.util.storage.IStorage;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.ImmutablePair;
import org.apache.commons.lang3.tuple.Pair;
import java.util.ArrayList;
import java.util.List;
/**
* <p>
@@ -44,7 +43,7 @@ import forge.util.storage.IStorage;
* @version $Id$
*/
public class CustomLimited extends DeckBase {
private final SealedProduct.Template tpl;
private final SealedTemplate tpl;
/**
* TODO: Write javadoc for Constructor.
@@ -57,7 +56,7 @@ public class CustomLimited extends DeckBase {
CardEdition edition = CardEdition.Predicates.getRandomSetWithAllBasicLands(FModel.getMagicDb().getEditions());
if(edition!=null)//can be null on lazy loading, probably does not work correctly then
landSetCode=edition.getCode();
tpl = new SealedProduct.Template(slots);
tpl = new SealedTemplate(slots);
}
private static final long serialVersionUID = 7435640939026612173L;
@@ -110,7 +109,7 @@ public class CustomLimited extends DeckBase {
slots.add(ImmutablePair.of(kv[1], Integer.parseInt(kv[0])));
}
} else
slots = SealedProduct.Template.genericDraftBooster.getSlots();
slots = SealedTemplate.genericDraftBooster.getSlots();
final CustomLimited cd = new CustomLimited(data.get("Name"), slots);
cd.landSetCode = data.get("LandSetCode");
@@ -172,9 +171,9 @@ public class CustomLimited extends DeckBase {
/**
* TODO: Write javadoc for this method.
* @return SealedProduct.Template
* @return SealedTemplate
*/
public SealedProduct.Template getSealedProductTemplate() {
public SealedTemplate getSealedProductTemplate() {
return tpl;
}

View File

@@ -28,7 +28,7 @@ import forge.deck.DeckSection;
import forge.gui.util.SGuiChoose;
import forge.gui.util.SOptionPane;
import forge.item.PaperCard;
import forge.item.SealedProduct;
import forge.item.SealedTemplate;
import forge.item.generation.IUnOpenedProduct;
import forge.item.generation.UnOpenedProduct;
import forge.localinstance.properties.ForgeConstants;
@@ -164,7 +164,7 @@ public class SealedCardPoolGenerator {
switch(poolType) {
case Full:
// Choose number of boosters
if (!chooseNumberOfBoosters(new UnOpenedProduct(SealedProduct.Template.genericDraftBooster))) {
if (!chooseNumberOfBoosters(new UnOpenedProduct(SealedTemplate.genericDraftBooster))) {
return;
}
landSetCode = CardEdition.Predicates.getRandomSetWithAllBasicLands(FModel.getMagicDb().getEditions()).getCode();
@@ -218,7 +218,7 @@ public class SealedCardPoolGenerator {
List<Pair<String, Integer>> promoSlot = new ArrayList<>();
promoSlot.add(Pair.of(pieces[1], num));
SealedProduct.Template promoProduct = new SealedProduct.Template("Prerelease Promo", promoSlot);
SealedTemplate promoProduct = new SealedTemplate("Prerelease Promo", promoSlot);
// Create a "booster" with just the promo card. Rarity + Edition into a Template
this.product.add(new UnOpenedProduct(promoProduct, FModel.getMagicDb().getCommonCards().getAllCards(chosenEdition)));

View File

@@ -17,21 +17,12 @@
*/
package forge.gamemodes.quest;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map.Entry;
import org.apache.commons.lang3.tuple.Pair;
import com.google.common.base.Function;
import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import forge.card.CardEdition;
import forge.card.CardRarity;
import forge.card.ICardDatabase;
@@ -45,16 +36,7 @@ import forge.gamemodes.quest.data.QuestAssets;
import forge.gamemodes.quest.data.QuestPreferences;
import forge.gamemodes.quest.data.QuestPreferences.DifficultyPrefs;
import forge.gamemodes.quest.data.QuestPreferences.QPref;
import forge.item.BoosterBox;
import forge.item.BoosterPack;
import forge.item.FatPack;
import forge.item.IPaperCard;
import forge.item.InventoryItem;
import forge.item.PaperCard;
import forge.item.PreconDeck;
import forge.item.SealedProduct;
import forge.item.SealedProduct.Template;
import forge.item.TournamentPack;
import forge.item.*;
import forge.item.generation.BoosterSlots;
import forge.item.generation.UnOpenedProduct;
import forge.localinstance.properties.ForgePreferences.FPref;
@@ -62,6 +44,13 @@ import forge.model.FModel;
import forge.util.Aggregates;
import forge.util.ItemPool;
import forge.util.MyRandom;
import org.apache.commons.lang3.tuple.Pair;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map.Entry;
/**
* This is a helper class to execute operations on QuestData. It has been
@@ -604,7 +593,7 @@ public final class QuestUtilCards {
*/
private void generateSinglesInShop(final int quantity) {
// This is the spot we need to change
SealedProduct.Template boosterTemplate = getShopBoosterTemplate();
SealedTemplate boosterTemplate = getShopBoosterTemplate();
if (questController.getFormat() == null) {
for (int i = 0; i < quantity; i++) {
questAssets.getShopList().addAllOfTypeFlat(new UnOpenedProduct(boosterTemplate).get());
@@ -726,25 +715,25 @@ public final class QuestUtilCards {
}
@SuppressWarnings("unchecked")
private SealedProduct.Template getShopBoosterTemplate() {
return new SealedProduct.Template(Lists.newArrayList(
private SealedTemplate getShopBoosterTemplate() {
return new SealedTemplate(Lists.newArrayList(
Pair.of(BoosterSlots.COMMON, questPreferences.getPrefInt(QPref.SHOP_SINGLES_COMMON)),
Pair.of(BoosterSlots.UNCOMMON, questPreferences.getPrefInt(QPref.SHOP_SINGLES_UNCOMMON)),
Pair.of(BoosterSlots.RARE_MYTHIC, questPreferences.getPrefInt(QPref.SHOP_SINGLES_RARE))
));
}
private SealedProduct.Template getBoosterTemplate() {
return new SealedProduct.Template(ImmutableList.of(
private SealedTemplate getBoosterTemplate() {
return new SealedTemplate(ImmutableList.of(
Pair.of(BoosterSlots.COMMON, questPreferences.getPrefInt(QPref.BOOSTER_COMMONS)),
Pair.of(BoosterSlots.UNCOMMON, questPreferences.getPrefInt(QPref.BOOSTER_UNCOMMONS)),
Pair.of(BoosterSlots.RARE_MYTHIC, questPreferences.getPrefInt(QPref.BOOSTER_RARES))
));
}
public static SealedProduct.Template getColoredBoosterTemplate(final String color) {
public static SealedTemplate getColoredBoosterTemplate(final String color) {
if (FModel.getQuest().getFormat() == null) {
return new Template("?", ImmutableList.of(
return new SealedTemplate("?", ImmutableList.of(
Pair.of(BoosterSlots.COMMON + ":color(\"" + color + "\"):!" + BoosterSlots.LAND, 11),
Pair.of(BoosterSlots.UNCOMMON + ":color(\"" + color + "\"):!" + BoosterSlots.LAND, 3),
Pair.of(BoosterSlots.RARE_MYTHIC + ":color(\"" + color + "\"):!" + BoosterSlots.LAND, 1),
@@ -764,7 +753,7 @@ public final class QuestUtilCards {
}
restrictions.append(")");
}
return new Template("?", ImmutableList.of(
return new SealedTemplate("?", ImmutableList.of(
Pair.of(BoosterSlots.COMMON + ":color(\"" + color + "\"):!" + BoosterSlots.LAND + restrictions, 11),
Pair.of(BoosterSlots.UNCOMMON + ":color(\"" + color + "\"):!" + BoosterSlots.LAND + restrictions, 3),
Pair.of(BoosterSlots.RARE_MYTHIC + ":color(\"" + color + "\"):!" + BoosterSlots.LAND + restrictions, 1),

View File

@@ -23,12 +23,9 @@ import java.util.EnumSet;
import java.util.List;
import java.util.Map;
import org.apache.commons.lang3.tuple.ImmutablePair;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import forge.card.CardEdition;
import forge.gamemodes.quest.data.QuestPreferences.QPref;
import forge.gamemodes.quest.io.ReadPriceList;
@@ -36,11 +33,14 @@ import forge.gui.GuiBase;
import forge.gui.util.SGuiChoose;
import forge.gui.util.SOptionPane;
import forge.item.PaperCard;
import forge.item.SealedProduct;
import forge.item.SealedTemplate;
import forge.item.generation.UnOpenedProduct;
import forge.model.FModel;
import forge.util.TextUtil;
import forge.util.storage.IStorage;
import org.apache.commons.lang3.tuple.ImmutablePair;
import java.util.*;
/**
* This is a helper class for unlocking new sets during a format-limited
@@ -192,8 +192,8 @@ public class QuestUtilUnlockSets {
* @param unlockedSet the edition to unlock
*/
public static void doUnlock(final QuestController qData, final CardEdition unlockedSet) {
IStorage<SealedProduct.Template> starters = FModel.getMagicDb().getTournamentPacks();
IStorage<SealedProduct.Template> boosters = FModel.getMagicDb().getBoosters();
IStorage<SealedTemplate> starters = FModel.getMagicDb().getTournamentPacks();
IStorage<SealedTemplate> boosters = FModel.getMagicDb().getBoosters();
qData.getFormat().unlockSet(unlockedSet.getCode());
String additionalSet = unlockedSet.getAdditionalUnlockSet();

View File

@@ -1,41 +1,24 @@
package forge.gamemodes.quest;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map.Entry;
import com.google.common.collect.Lists;
import forge.gui.GuiBase;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.Pair;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;
import forge.LobbyPlayer;
import forge.card.CardEdition;
import forge.game.GameEndReason;
import forge.game.GameFormat;
import forge.game.GameOutcome;
import forge.game.GameView;
import forge.game.player.GameLossReason;
import forge.game.player.PlayerOutcome;
import forge.game.player.PlayerStatistics;
import forge.game.player.PlayerView;
import forge.game.player.RegisteredPlayer;
import forge.game.player.*;
import forge.gamemodes.quest.bazaar.QuestItemType;
import forge.gamemodes.quest.data.QuestPreferences;
import forge.gamemodes.quest.data.QuestPreferences.DifficultyPrefs;
import forge.gamemodes.quest.data.QuestPreferences.QPref;
import forge.gui.GuiBase;
import forge.gui.interfaces.IButton;
import forge.gui.interfaces.IWinLoseView;
import forge.gui.util.SGuiChoose;
import forge.item.BoosterPack;
import forge.item.*;
import forge.item.IPaperCard.Predicates;
import forge.item.InventoryItem;
import forge.item.PaperCard;
import forge.item.SealedProduct;
import forge.item.TournamentPack;
import forge.item.generation.BoosterSlots;
import forge.item.generation.IUnOpenedProduct;
import forge.item.generation.UnOpenedProduct;
@@ -46,6 +29,13 @@ import forge.player.GamePlayerUtil;
import forge.util.Localizer;
import forge.util.MyRandom;
import forge.util.TextUtil;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.Pair;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map.Entry;
public class QuestWinLoseController {
private final GameView lastGame;
@@ -543,7 +533,7 @@ public class QuestWinLoseController {
final List<String> sets = new ArrayList<>();
for (final SealedProduct.Template bd : FModel.getMagicDb().getBoosters()) {
for (final SealedTemplate bd : FModel.getMagicDb().getBoosters()) {
if (bd != null && qData.getFormat().isSetLegal(bd.getEdition())) {
sets.add(bd.getEdition());
}
@@ -612,8 +602,8 @@ public class QuestWinLoseController {
}
}
private SealedProduct.Template getBoosterTemplate() {
return new SealedProduct.Template(ImmutableList.of(
private SealedTemplate getBoosterTemplate() {
return new SealedTemplate(ImmutableList.of(
Pair.of(BoosterSlots.COMMON, FModel.getQuestPreferences().getPrefInt(QPref.BOOSTER_COMMONS)),
Pair.of(BoosterSlots.UNCOMMON, FModel.getQuestPreferences().getPrefInt(QPref.BOOSTER_UNCOMMONS)),
Pair.of(BoosterSlots.RARE_MYTHIC, FModel.getQuestPreferences().getPrefInt(QPref.BOOSTER_RARES))

View File

@@ -18,21 +18,20 @@
package forge.model;
import java.io.File;
import java.util.List;
import com.google.common.base.Predicate;
import forge.gamemodes.limited.CustomLimited;
import forge.gamemodes.limited.SealedCardPoolGenerator;
import forge.item.IPaperCard;
import forge.item.PaperCard;
import forge.item.SealedProduct;
import forge.item.SealedTemplate;
import forge.item.generation.IUnOpenedProduct;
import forge.item.generation.UnOpenedProduct;
import forge.localinstance.properties.ForgeConstants;
import forge.util.FileUtil;
import java.io.File;
import java.util.List;
/**
* The class MetaSet. This class is used to define 'special'
* sets within a (fantasy) block, like custom sets (cubes),
@@ -166,7 +165,7 @@ public class MetaSet {
switch(type) {
case Full:
return new UnOpenedProduct(SealedProduct.Template.genericDraftBooster);
return new UnOpenedProduct(SealedTemplate.genericDraftBooster);
case Booster:
return new UnOpenedProduct(FModel.getMagicDb().getBoosters().get(data));
@@ -179,7 +178,7 @@ public class MetaSet {
case JoinedSet:
Predicate<PaperCard> predicate = IPaperCard.Predicates.printedInSets(data.split(" "));
return new UnOpenedProduct(SealedProduct.Template.genericDraftBooster, predicate);
return new UnOpenedProduct(SealedTemplate.genericDraftBooster, predicate);
case Choose: return UnOpenedMeta.choose(data);
case Random: return UnOpenedMeta.random(data);
@@ -199,7 +198,7 @@ public class MetaSet {
List<String> dfData = FileUtil.readFile(ForgeConstants.SEALED_DIR + data + SealedCardPoolGenerator.FILE_EXT);
final CustomLimited myCube = CustomLimited.parse(dfData, FModel.getDecks().getCubes());
SealedProduct.Template fnPick = myCube.getSealedProductTemplate();
SealedTemplate fnPick = myCube.getSealedProductTemplate();
return new UnOpenedProduct(fnPick, myCube.getCardPool());
default: return null;