Added new MetaSet types and functionality to support guild boosters in RtR Sealed. New types: choose1, random1, and combo, plus auxiliary types booster and pack.

This commit is contained in:
RumbleBBU
2012-09-25 09:53:07 +00:00
parent 8eb157606d
commit b32daa1ae1
7 changed files with 395 additions and 20 deletions

1
.gitattributes vendored
View File

@@ -12044,6 +12044,7 @@ src/main/java/forge/card/FormatCollection.java -text
src/main/java/forge/card/MetaSet.java -text src/main/java/forge/card/MetaSet.java -text
src/main/java/forge/card/MtgDataParser.java -text src/main/java/forge/card/MtgDataParser.java -text
src/main/java/forge/card/TriggerReplacementBase.java -text src/main/java/forge/card/TriggerReplacementBase.java -text
src/main/java/forge/card/UnOpenedMeta.java -text
src/main/java/forge/card/UnOpenedProduct.java -text src/main/java/forge/card/UnOpenedProduct.java -text
src/main/java/forge/card/abilityfactory/AbilityFactory.java svneol=native#text/plain src/main/java/forge/card/abilityfactory/AbilityFactory.java svneol=native#text/plain
src/main/java/forge/card/abilityfactory/AbilityFactoryAlterLife.java svneol=native#text/plain src/main/java/forge/card/abilityfactory/AbilityFactoryAlterLife.java svneol=native#text/plain

View File

@@ -300,8 +300,6 @@ public final class CardBlock implements Comparable<CardBlock> {
*/ */
public UnOpenedProduct getBooster(final String code) { public UnOpenedProduct getBooster(final String code) {
System.out.println("Booster called...");
if (this.getNumberMetaSets() < 1) { if (this.getNumberMetaSets() < 1) {
throw new RuntimeException("Attempted to get a booster pack for empty metasets."); throw new RuntimeException("Attempted to get a booster pack for empty metasets.");
} }

View File

@@ -1,6 +1,25 @@
/*
* Forge: Play Magic: the Gathering.
* Copyright (C) 2011 Forge Team
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package forge.card; package forge.card;
import java.io.File; import java.io.File;
import java.util.ArrayList;
import java.util.List; import java.util.List;
import forge.Singletons; import forge.Singletons;
@@ -23,7 +42,8 @@ import forge.util.closures.Lambda1;
* *
* where "X" is an integer from 0...8 (just like for sets) * where "X" is an integer from 0...8 (just like for sets)
* *
* "A" is either "cube", "meta", or "full". * "A" is either "cube", "meta", "full", "choose1", "random1",
* "set", "pack", or "combo".
* *
* "full" uses all available cards for this booster, just like * "full" uses all available cards for this booster, just like
* the full cardpool option. The values of "B" and "C" are not * the full cardpool option. The values of "B" and "C" are not
@@ -47,6 +67,28 @@ import forge.util.closures.Lambda1;
* "C" is the name that is displayed for this meta-booster * "C" is the name that is displayed for this meta-booster
* in the set selection menu. * in the set selection menu.
* *
* The new types added after beta 1.2.14:
*
* "choose1": define several metasets in a semicolon-separated (;)
* list in value B, the player will choose one of them.
*
* "random1": like choose1, except that the player will get a
* random pack.
*
* "combo": define several metasets in a semicolon-separated (;)
* list in value B, the booster will be based on the combined
* cardpool of all these. Note that if one of the metasets is
* a "full", the rest are irrelevant.
*
* "booster": generate a single booster based on value B set. (You
* should use this only for combo, choose1 and random1 metasets,
* otherwise use normal Sets instead of MetaSets in the block
* definition!)
*
* "pack": like set, but attempts to generate a starter pack instead
* of a booster. If starter packs are not available for value B set,
* a booster is generated instead.
*
*/ */
public class MetaSet { public class MetaSet {
@@ -64,24 +106,40 @@ public class MetaSet {
*/ */
public MetaSet(final String creationString) { public MetaSet(final String creationString) {
final String[] kv = creationString.split("/", 3);
String[] kv = new String [3];
kv[0] = creationString.substring(0, creationString.indexOf('/'));
kv[1] = creationString.substring(creationString.indexOf('/') + 1, creationString.lastIndexOf('/'));
kv[2] = creationString.substring(creationString.lastIndexOf('/') + 1);
// Display the parse results:
// System.out.println("KV = '" + kv[0] + "', '" + kv[1] + "', '" + kv[2] + "'");
type = kv[0]; type = kv[0];
data = kv[1]; data = kv[1];
// boosterGen = null;
if ("cube".equalsIgnoreCase(type)) { if ("cube".equalsIgnoreCase(type)) {
code = "*C:" + kv[2]; code = "*C:" + kv[2];
//System.out.println("Created a CUBE, code '" + code + "'");
} }
else if ("full".equalsIgnoreCase(type)) { else if ("full".equalsIgnoreCase(type)) {
code = "*FULL"; code = "*FULL";
//System.out.println("Selecting from FULL cardpool'" + code + "'");
} }
else if ("meta".equalsIgnoreCase(type)) { else if ("meta".equalsIgnoreCase(type)) {
code = "*B:" + kv[2]; code = "*B:" + kv[2];
//System.out.println("Created a META set of " + kv[1] + ", code '" + code + "'"); }
else if ("choose1".equalsIgnoreCase(type)) {
code = "*!:" + kv[2];
}
else if ("random1".equalsIgnoreCase(type)) {
code = "*?:" + kv[2];
}
else if ("combo".equalsIgnoreCase(type)) {
code = "*+:" + kv[2];
}
else if ("booster".equalsIgnoreCase(type)) {
code = "*" + kv[2];
}
else if ("pack".equalsIgnoreCase(type)) {
code = "*" + kv[2] + "(S)";
} }
else { else {
code = null; code = null;
@@ -108,7 +166,12 @@ public class MetaSet {
*/ */
public UnOpenedProduct getBooster() { public UnOpenedProduct getBooster() {
//System.out.println("MetaSet.booster called..."); ItemPool<CardPrinted> cardPool = null;
if ("meta".equalsIgnoreCase(type) || "choose1".equalsIgnoreCase(type)
|| "random1".equalsIgnoreCase(type) || "combo".equalsIgnoreCase(type)) {
cardPool = new ItemPool<CardPrinted>(CardPrinted.class);
}
if ("cube".equalsIgnoreCase(type)) { if ("cube".equalsIgnoreCase(type)) {
@@ -144,16 +207,14 @@ public class MetaSet {
return new UnOpenedProduct(fnPick, bpCustom); return new UnOpenedProduct(fnPick, bpCustom);
} }
else if ("full".equalsIgnoreCase(type)) { else if ("full".equalsIgnoreCase(type)) {
// System.out.println("Initializing boosters for FULL cardpool");
final BoosterGenerator bpFull = new BoosterGenerator(CardDb.instance().getAllUniqueCards()); final BoosterGenerator bpFull = new BoosterGenerator(CardDb.instance().getAllUniqueCards());
return new UnOpenedProduct(BoosterGenerator.IDENTITY_PICK, bpFull); return new UnOpenedProduct(BoosterGenerator.IDENTITY_PICK, bpFull);
} }
else if ("meta".equalsIgnoreCase(type)) { else if ("meta".equalsIgnoreCase(type)) {
// System.out.println("Initializing boosters for " + data);
// NOTE: The following code is far from ideal in a number of ways. If someone can // NOTE: The following code is far from ideal in a number of ways. If someone can
// think of a way to improve it, please do so. --BBU // think of a way to improve it, please do so. --BBU
ItemPool<CardPrinted> cardPool = new ItemPool<CardPrinted>(CardPrinted.class); // ItemPool<CardPrinted> cardPool = new ItemPool<CardPrinted>(CardPrinted.class);
for (CardPrinted aCard : CardDb.instance().getAllCards()) { for (CardPrinted aCard : CardDb.instance().getAllCards()) {
if (data.indexOf(aCard.getEdition()) > -1) { if (data.indexOf(aCard.getEdition()) > -1) {
cardPool.add(aCard); cardPool.add(aCard);
@@ -163,9 +224,94 @@ public class MetaSet {
final BoosterGenerator bpSets = new BoosterGenerator(cardPool); final BoosterGenerator bpSets = new BoosterGenerator(cardPool);
return new UnOpenedProduct(BoosterGenerator.IDENTITY_PICK, bpSets); return new UnOpenedProduct(BoosterGenerator.IDENTITY_PICK, bpSets);
} else if ("booster".equalsIgnoreCase(type)) {
return new UnOpenedProduct(Singletons.getModel().getBoosters().get(data));
} else if ("pack".equalsIgnoreCase(type)) {
return new UnOpenedProduct(Singletons.getModel().getTournamentPacks().get(data));
} else if ("choose1".equalsIgnoreCase(type)) {
return new UnOpenedMeta(data, true);
} else if ("random1".equalsIgnoreCase(type)) {
return new UnOpenedMeta(data, false);
} else if ("combo".equalsIgnoreCase(type)) {
final BoosterGenerator bpSets = new BoosterGenerator(buildPool(data));
return new UnOpenedProduct(BoosterGenerator.IDENTITY_PICK, bpSets);
} }
else { else {
throw new RuntimeException("Cannot initialize boosters for: " + type); throw new RuntimeException("Cannot initialize boosters for: " + type);
} }
} }
/**
* Build a cardpool for the 'combo' special MetaSet type.
*
* @param creationString
* the data that contains a collection of semicolon-separated metaset definitions
* @return ItemPool<CardPrinted>
* the collection of cards
*
*/
private ItemPool<CardPrinted> buildPool(final String creationString) {
ItemPool<CardPrinted> cardPool = new ItemPool<CardPrinted>(CardPrinted.class);
List<MetaSet> metaSets = new ArrayList<MetaSet>();
final String[] metas = creationString.split(";");
for (int i = 0; i < metas.length; i++) {
final String [] typeTest = metas[i].split("/");
if (typeTest[0].equalsIgnoreCase("choose1") || typeTest[0].equalsIgnoreCase("random1")
|| typeTest[0].equalsIgnoreCase("combo")) {
System.out.println("WARNING - MetaSet type '" + typeTest[0] + "' ignored in pool creation.");
}
else if (typeTest[0].equalsIgnoreCase("full")) {
for (CardPrinted aCard : CardDb.instance().getAllUniqueCards()) {
cardPool.add(aCard);
}
return cardPool;
}
final MetaSet addMeta = new MetaSet(metas[i]);
metaSets.add(addMeta);
}
if (metaSets.size() < 1) {
return null;
}
for (MetaSet mSet : metaSets) {
if (mSet.type.equalsIgnoreCase("meta") || mSet.type.equalsIgnoreCase("booster")
|| mSet.type.equalsIgnoreCase("pack")) {
final String mData = new String(mSet.data);
for (CardPrinted aCard : CardDb.instance().getAllCards()) {
if (mData.indexOf(aCard.getEdition()) > -1) {
if (!cardPool.contains(aCard)) {
cardPool.add(aCard);
// System.out.println(mSet.type + " " + mData + ": Added card: " + aCard.getName());
}
}
}
} else if (mSet.type.equalsIgnoreCase("cube")) {
final File dFolder = new File("res/sealed/");
if (!dFolder.exists()) {
throw new RuntimeException("GenerateSealed : folder not found -- folder is "
+ dFolder.getAbsolutePath());
}
if (!dFolder.isDirectory()) {
throw new RuntimeException("GenerateSealed : not a folder -- " + dFolder.getAbsolutePath());
}
List<String> dfData = FileUtil.readFile("res/sealed/" + mSet.data + ".sealed");
final CustomLimited myCube = CustomLimited.parse(dfData, Singletons.getModel().getDecks().getCubes());
for (CardPrinted aCard : myCube.getCardPool().toFlatList()) {
if (!cardPool.contains(aCard)) {
cardPool.add(aCard);
// System.out.println(mSet.type + " " + mSet.data + ": Added card: " + aCard.getName());
}
}
}
}
return cardPool;
}
} }

View File

@@ -0,0 +1,189 @@
/*
* Forge: Play Magic: the Gathering.
* Copyright (C) 2011 Forge Team
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package forge.card;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import forge.Singletons;
import forge.gui.GuiUtils;
import forge.item.CardPrinted;
import forge.util.MyRandom;
/**
* This type extends UnOpenedMeta to support booster choice or random boosters
* in sealed deck games. See MetaSet.java for further information.
*
*/
public class UnOpenedMeta extends UnOpenedProduct {
private final ArrayList<MetaSet> metaSets;
private final boolean choice;
private List<String> partiality;
private final int partialityPreference = 80;
private final Random generator = MyRandom.getRandom();
/**
* Constructor for UnOpenedMeta.
* @param creationString
* String, is parsed for MetaSet info.
* @param choose
* sets the random/choice status.
*/
public UnOpenedMeta(final String creationString, final boolean choose) {
// NOTE: we need to call the super constructor with something non-null,
// but it doesn't matter with what exactly, since we are overriding it
// in open() anyway. I'm using Portal because that makes it easier to
// spot if the code is misbehaving in certain ways. --BBU
super(Singletons.getModel().getBoosters().get("POR"));
metaSets = new ArrayList<MetaSet>();
choice = choose;
final String[] metas = creationString.split(";");
partiality = null;
for (int i = 0; i < metas.length; i++) {
final MetaSet addMeta = new MetaSet(metas[i]);
metaSets.add(addMeta);
}
}
/**
* Adds to partiality info.
* @param addString
* String, add partiality for this String.
*/
private void addPartiality(final String addString) {
if (!hasPartiality(addString)) {
partiality.add(addString);
}
}
/**
* Checks if the AI has a partiality for this set.
* @param partialString
* String, check partiality for this.
*/
private boolean hasPartiality(final String partialString) {
if (partiality.isEmpty()) {
return false;
}
for (final String cmp : partiality) {
if (partialString.equals(cmp)) {
return true;
}
}
return false;
}
/**
* Open the booster pack, return contents.
* @return List, list of cards.
*/
@Override
public List<CardPrinted> open() {
return this.open(true, null);
}
/**
* Like open, can define whether is human or not.
* @param isHuman
* boolean, is human player?
* @param partialities
* known partialities for the AI.
* @return List, list of cards.
*/
@Override
public List<CardPrinted> open(final boolean isHuman, List<String> partialities) {
if (metaSets.size() < 1) {
throw new RuntimeException("Empty UnOpenedMetaset, cannot generate booster.");
}
if (choice) {
if (isHuman) {
final List<String> choices = new ArrayList<String>();
for (MetaSet meta : metaSets) {
choices.add(meta.getCode());
}
final Object o = GuiUtils.chooseOne("Choose booster:", choices);
for (int i = 0; i < metaSets.size(); i++) {
if (o.toString().equals(metaSets.get(i).getCode())) {
final UnOpenedProduct newBooster = metaSets.get(i).getBooster();
return newBooster.open();
}
}
throw new RuntimeException("Could not find MetaSet " + o.toString());
}
else {
partiality = partialities;
int selected = -1;
if (partiality == null || partiality.isEmpty()) {
// System.out.println("No partiality yet");
selected = generator.nextInt(metaSets.size());
// System.out.println("AI randomly chose " + metaSets.get(selected).getCode());
if (partiality != null) {
addPartiality(metaSets.get(selected).getCode());
}
}
else {
for (int i = 0; i < metaSets.size(); i++) {
if (hasPartiality(metaSets.get(i).getCode()) && MyRandom.percentTrue(partialityPreference)) {
// System.out.println("AI chose " + metaSets.get(i).getCode() + " because of partiality.");
selected = i;
break;
}
}
}
if (selected == -1) {
selected = generator.nextInt(metaSets.size());
if (partiality != null) {
addPartiality(metaSets.get(selected).getCode());
}
// System.out.println("AI chose " + metaSets.get(selected).getCode() + " because partiality not established or failed percentage test.");
}
final UnOpenedProduct newBooster = metaSets.get(selected).getBooster();
return newBooster.open();
}
}
else {
int selected = generator.nextInt(metaSets.size());
// System.out.println("RANDOMLY got " + metaSets.get(selected).getCode());
// It may actually seem slightly unfair to allow the computer change its partialities based
// on the random sets it gets since the player can't do the same...but, OTOH, this could also
// work against the computer, if this results in a bad partiality choice. --BBU
if (!isHuman && partiality != null && MyRandom.percentTrue(partialityPreference)) {
addPartiality(metaSets.get(selected).getCode());
// System.out.println("AI decided to add " + metaSets.get(selected).getCode() + " to partialities.");
}
final UnOpenedProduct newBooster = metaSets.get(selected).getBooster();
return newBooster.open();
}
}
}

View File

@@ -35,4 +35,16 @@ public class UnOpenedProduct {
return openBooster != null ? openBooster.apply(generator) : generator.getBoosterPack(booster); return openBooster != null ? openBooster.apply(generator) : generator.getBoosterPack(booster);
} }
/**
* Like open, can define whether is human or not.
* @param isHuman
* boolean, is human player?
* @param partialities
* known partialities for the AI.
* @return List, list of cards.
*/
public List<CardPrinted> open(final boolean isHuman, List<String> partialities) {
return open();
}
} }

View File

@@ -46,6 +46,7 @@ import forge.util.closures.Lambda1;
*/ */
public class SealedDeckFormat { public class SealedDeckFormat {
private final ArrayList<UnOpenedProduct> product = new ArrayList<UnOpenedProduct>(); private final ArrayList<UnOpenedProduct> product = new ArrayList<UnOpenedProduct>();
private List<String> partiality;
/** The Land set code. */ /** The Land set code. */
private String[] landSetCode = { "" }; private String[] landSetCode = { "" };
@@ -60,6 +61,8 @@ public class SealedDeckFormat {
*/ */
public SealedDeckFormat(final String sealedType) { public SealedDeckFormat(final String sealedType) {
partiality = new ArrayList<String>();
if (sealedType.equals("Full")) { if (sealedType.equals("Full")) {
final BoosterGenerator bpFull = new BoosterGenerator(CardDb.instance().getAllUniqueCards()); final BoosterGenerator bpFull = new BoosterGenerator(CardDb.instance().getAllUniqueCards());
@@ -104,7 +107,6 @@ public class SealedDeckFormat {
final int nPacks = block.getCntBoostersSealed(); final int nPacks = block.getCntBoostersSealed();
if (block.getNumberMetaSets() > 0) { if (block.getNumberMetaSets() > 0) {
System.out.println("Metasets found ");
int j = cardSets.length; int j = cardSets.length;
@@ -211,7 +213,13 @@ public class SealedDeckFormat {
} }
} }
} else { } else {
final UnOpenedProduct product1 = new UnOpenedProduct(Singletons.getModel().getBoosters().get(sets[0])); UnOpenedProduct product1;
if (sets[0].charAt(0) == '*') {
product1 = block.getBooster(sets[0]);
}
else {
product1 = new UnOpenedProduct(Singletons.getModel().getBoosters().get(sets[0]));
}
for (int i = 0; i < nPacks; i++) { for (int i = 0; i < nPacks; i++) {
this.product.add(product1); this.product.add(product1);
} }
@@ -411,15 +419,36 @@ public class SealedDeckFormat {
* @return a {@link forge.CardList} object. * @return a {@link forge.CardList} object.
*/ */
public ItemPool<CardPrinted> getCardpool() { public ItemPool<CardPrinted> getCardpool() {
return getCardpool(true);
}
/**
* <p>
* getCardpool.
* </p>
*
* @param isHuman
* boolean, get pool for human (possible choices)
* @return a {@link forge.CardList} object.
*/
public ItemPool<CardPrinted> getCardpool(final boolean isHuman) {
if (!isHuman) {
if (!partiality.isEmpty()) {
partiality.clear();
}
}
final ItemPool<CardPrinted> pool = new ItemPool<CardPrinted>(CardPrinted.class); final ItemPool<CardPrinted> pool = new ItemPool<CardPrinted>(CardPrinted.class);
for (int i = 0; i < this.product.size(); i++) { for (int i = 0; i < this.product.size(); i++) {
pool.addAllFlat(this.product.get(i).open()); pool.addAllFlat(this.product.get(i).open(isHuman, partiality));
} }
return pool; return pool;
} }
/** /**
* Gets the land set code. * Gets the land set code.
* *

View File

@@ -167,7 +167,7 @@ public enum CSubmenuSealed implements ICDoc {
+ ">> does not equal any of the sealedTypes."); + ">> does not equal any of the sealedTypes.");
} }
if (sd.getCardpool().isEmpty()) { if (sd.getCardpool(false).isEmpty()) {
return; return;
} }
@@ -203,8 +203,8 @@ public enum CSubmenuSealed implements ICDoc {
sealedDecks.delete(sDeckName); sealedDecks.delete(sDeckName);
} }
final ItemPool<CardPrinted> sDeck = sd.getCardpool(); final ItemPool<CardPrinted> sDeck = sd.getCardpool(true);
ItemPool<CardPrinted> aiDecks = sd.getCardpool(); ItemPool<CardPrinted> aiDecks = sd.getCardpool(false);
final Deck deck = new Deck(sDeckName); final Deck deck = new Deck(sDeckName);
deck.getSideboard().addAll(sDeck); deck.getSideboard().addAll(sDeck);
@@ -218,7 +218,7 @@ public enum CSubmenuSealed implements ICDoc {
for (int i = 0; i < rounds; i++) { for (int i = 0; i < rounds; i++) {
if (i > 0) { if (i > 0) {
// Re-randomize for AI decks beyond the first... // Re-randomize for AI decks beyond the first...
aiDecks = sd.getCardpool(); aiDecks = sd.getCardpool(false);
} }
sealed.addAiDeck(new SealedDeck(aiDecks.toFlatList()).buildDeck()); sealed.addAiDeck(new SealedDeck(aiDecks.toFlatList()).buildDeck());
} }