Refactor Planar Conquest code so planes and regions can be loaded from resource files

This commit is contained in:
drdev
2016-01-31 00:16:20 +00:00
parent deb88ce8ab
commit 16f0898842
22 changed files with 501 additions and 666 deletions

View File

@@ -29,6 +29,7 @@ import forge.item.PaperCard;
import forge.model.FModel;
import forge.planarconquest.ConquestCommander;
import forge.planarconquest.ConquestPlane;
import forge.planarconquest.ConquestRegion;
import forge.quest.QuestWorld;
import forge.util.gui.SGuiChoose;
import forge.util.gui.SOptionPane;
@@ -74,7 +75,7 @@ public class AdvancedSearch {
return FModel.getFormats().getAllFormatsOfCard(input);
}
}),
CARD_PLANE("Plane", PaperCard.class, FilterOperator.MULTI_LIST_OPS, new CustomListEvaluator<PaperCard, ConquestPlane>(ImmutableList.copyOf(ConquestPlane.values())) {
CARD_PLANE("Plane", PaperCard.class, FilterOperator.MULTI_LIST_OPS, new CustomListEvaluator<PaperCard, ConquestPlane>(ImmutableList.copyOf(FModel.getPlanes())) {
@Override
protected ConquestPlane getItemValue(PaperCard input) {
throw new RuntimeException("getItemValues should be called instead");
@@ -84,14 +85,14 @@ public class AdvancedSearch {
return ConquestPlane.getAllPlanesOfCard(input);
}
}),
CARD_REGION("Region", PaperCard.class, FilterOperator.MULTI_LIST_OPS, new CustomListEvaluator<PaperCard, ConquestPlane.Region>(ConquestPlane.getAllRegions()) {
CARD_REGION("Region", PaperCard.class, FilterOperator.MULTI_LIST_OPS, new CustomListEvaluator<PaperCard, ConquestRegion>(ConquestRegion.getAllRegions()) {
@Override
protected ConquestPlane.Region getItemValue(PaperCard input) {
protected ConquestRegion getItemValue(PaperCard input) {
throw new RuntimeException("getItemValues should be called instead");
}
@Override
protected Set<ConquestPlane.Region> getItemValues(PaperCard input) {
return ConquestPlane.getAllRegionsOfCard(input);
protected Set<ConquestRegion> getItemValues(PaperCard input) {
return ConquestRegion.getAllRegionsOfCard(input);
}
}),
CARD_QUEST_WORLD("Quest World", PaperCard.class, FilterOperator.MULTI_LIST_OPS, new CustomListEvaluator<PaperCard, QuestWorld>(ImmutableList.copyOf(FModel.getWorlds())) {
@@ -316,7 +317,7 @@ public class AdvancedSearch {
return input.getName();
}
}),
COMMANDER_ORIGIN("Origin", ConquestCommander.class, FilterOperator.SINGLE_LIST_OPS, new CustomListEvaluator<ConquestCommander, ConquestPlane>(Arrays.asList(ConquestPlane.values())) {
COMMANDER_ORIGIN("Origin", ConquestCommander.class, FilterOperator.SINGLE_LIST_OPS, new CustomListEvaluator<ConquestCommander, ConquestPlane>(ImmutableList.copyOf(FModel.getPlanes())) {
@Override
protected ConquestPlane getItemValue(ConquestCommander input) {
return input.getOriginPlane();

View File

@@ -35,6 +35,7 @@ import forge.interfaces.IProgressBar;
import forge.itemmanager.ItemManagerConfig;
import forge.limited.GauntletMini;
import forge.planarconquest.ConquestController;
import forge.planarconquest.ConquestPlane;
import forge.planarconquest.ConquestPreferences;
import forge.player.GamePlayerUtil;
import forge.properties.ForgeConstants;
@@ -83,6 +84,7 @@ public final class FModel {
private static IStorage<CardBlock> blocks;
private static IStorage<CardBlock> fantasyBlocks;
private static IStorage<ConquestPlane> planes;
private static IStorage<QuestWorld> worlds;
private static GameFormat.Collection formats;
@@ -155,6 +157,7 @@ public final class FModel {
questPreferences = new QuestPreferences();
conquestPreferences = new ConquestPreferences();
fantasyBlocks = new StorageBase<>("Custom blocks", new CardBlock.Reader(ForgeConstants.BLOCK_DATA_DIR + "fantasyblocks.txt", magicDb.getEditions()));
planes = new StorageBase<>("Conquest planes", new ConquestPlane.Reader(ForgeConstants.CONQUEST_PLANES_DIR + "planes.txt"));
worlds = new StorageBase<>("Quest worlds", new QuestWorld.Reader(ForgeConstants.QUEST_WORLD_DIR + "worlds.txt"));
loadDynamicGamedata();
@@ -301,6 +304,10 @@ public final class FModel {
return decks;
}
public static IStorage<ConquestPlane> getPlanes() {
return planes;
}
public static IStorage<QuestWorld> getWorlds() {
return worlds;
}

View File

@@ -0,0 +1,113 @@
package forge.planarconquest;
import java.util.ArrayList;
import java.util.List;
import forge.item.PaperCard;
import forge.model.FModel;
import forge.planarconquest.ConquestPreferences.CQPref;
import forge.util.Aggregates;
public class ConquestAwardPool {
private final BoosterPool commons, uncommons, rares, mythics;
private final int commonValue, uncommonValue, rareValue, mythicValue;
public ConquestAwardPool(Iterable<PaperCard> cards) {
ConquestPreferences prefs = FModel.getConquestPreferences();
commons = new BoosterPool();
uncommons = new BoosterPool();
rares = new BoosterPool();
mythics = new BoosterPool();
for (PaperCard c : cards) {
switch (c.getRarity()) {
case Common:
commons.add(c);
break;
case Uncommon:
uncommons.add(c);
break;
case Rare:
case Special: //lump special cards in with rares for simplicity
rares.add(c);
break;
case MythicRare:
mythics.add(c);
break;
default:
break;
}
}
//calculate odds of each rarity
float commonOdds = commons.getOdds(prefs.getPrefInt(CQPref.BOOSTER_COMMONS));
float uncommonOdds = uncommons.getOdds(prefs.getPrefInt(CQPref.BOOSTER_UNCOMMONS));
int raresPerBooster = prefs.getPrefInt(CQPref.BOOSTER_RARES);
float rareOdds = rares.getOdds(raresPerBooster);
float mythicOdds = mythics.getOdds((float)raresPerBooster / (float)prefs.getPrefInt(CQPref.BOOSTERS_PER_MYTHIC));
//determine value of each rarity based on the base value of a common
commonValue = prefs.getPrefInt(CQPref.AETHER_BASE_VALUE);
uncommonValue = Math.round(commonValue / (uncommonOdds / commonOdds));
rareValue = Math.round(commonValue / (rareOdds / commonOdds));
mythicValue = mythics.isEmpty() ? 0 : Math.round(commonValue / (mythicOdds / commonOdds));
}
public int getShardValue(PaperCard card) {
switch (card.getRarity()) {
case Common:
return commonValue;
case Uncommon:
return uncommonValue;
case Rare:
case Special:
return rareValue;
case MythicRare:
return mythicValue;
default:
return 0;
}
}
public BoosterPool getCommons() {
return commons;
}
public BoosterPool getUncommons() {
return uncommons;
}
public BoosterPool getRares() {
return rares;
}
public BoosterPool getMythics() {
return mythics;
}
public class BoosterPool {
private final List<PaperCard> cards = new ArrayList<PaperCard>();
private BoosterPool() {
}
public boolean isEmpty() {
return cards.isEmpty();
}
private float getOdds(float perBoosterCount) {
int count = cards.size();
if (count == 0) { return 0; }
return (float)perBoosterCount / (float)count;
}
private void add(PaperCard c) {
cards.add(c);
}
public void rewardCard(List<PaperCard> rewards) {
int index = Aggregates.randomInt(0, cards.size() - 1);
PaperCard c = cards.get(index);
cards.remove(index);
rewards.add(c);
}
}
}

View File

@@ -11,7 +11,6 @@ import forge.interfaces.IButton;
import forge.interfaces.IGuiGame;
import forge.interfaces.IWinLoseView;
import forge.model.FModel;
import forge.planarconquest.ConquestPlane.AwardPool;
import forge.planarconquest.ConquestPreferences.CQPref;
import forge.properties.ForgeConstants;
import forge.quest.QuestEventDifficulty;
@@ -23,7 +22,7 @@ import forge.util.Aggregates;
public class ConquestChaosBattle extends ConquestEvent {
private final QuestWorld world;
private final QuestEventDuel duel;
private AwardPool awardPool;
private ConquestAwardPool awardPool;
private boolean finished;
public ConquestChaosBattle() {
@@ -114,9 +113,9 @@ public class ConquestChaosBattle extends ConquestEvent {
finished = true;
}
public AwardPool getAwardPool() {
public ConquestAwardPool getAwardPool() {
if (awardPool == null) { //delay initializing until needed
awardPool = new AwardPool(world.getAllCards());
awardPool = new ConquestAwardPool(world.getAllCards());
}
return awardPool;
}

View File

@@ -5,7 +5,6 @@ import forge.deck.generation.DeckGenPool;
import forge.item.InventoryItem;
import forge.item.PaperCard;
import forge.model.FModel;
import forge.planarconquest.ConquestPlane.Region;
import forge.util.XmlReader;
import forge.util.XmlWriter;
import forge.util.XmlWriter.IXmlWritable;
@@ -35,11 +34,11 @@ public class ConquestCommander implements InventoryItem, IXmlWritable {
//determine origin of commander
ConquestPlane originPlane0 = null;
String originRegionName0 = null;
for (ConquestPlane plane : ConquestPlane.values()) {
for (ConquestPlane plane : FModel.getPlanes()) {
if (plane.getCommanders().contains(card)) {
originPlane0 = plane;
for (Region region : plane.getRegions()) {
if (region.getCommanders().contains(card)) {
for (ConquestRegion region : plane.getRegions()) {
if (region.getCardPool().contains(card)) {
originRegionName0 = region.getName();
break;
}

View File

@@ -40,7 +40,6 @@ import forge.interfaces.IWinLoseView;
import forge.item.PaperCard;
import forge.match.HostedMatch;
import forge.model.FModel;
import forge.planarconquest.ConquestPlane.AwardPool;
import forge.planarconquest.ConquestPreferences.CQPref;
import forge.player.GamePlayerUtil;
import forge.player.LobbyPlayerHuman;
@@ -183,7 +182,7 @@ public class ConquestController {
activeEvent = null;
}
public List<ConquestReward> awardBooster(AwardPool pool) {
public List<ConquestReward> awardBooster(ConquestAwardPool pool) {
ConquestPreferences prefs = FModel.getConquestPreferences();
List<PaperCard> rewards = new ArrayList<PaperCard>();
int boostersPerMythic = prefs.getPrefInt(CQPref.BOOSTERS_PER_MYTHIC);
@@ -233,7 +232,7 @@ public class ConquestController {
public int calculateShardCost(ItemPool<PaperCard> filteredCards, int unfilteredCount) {
if (filteredCards.isEmpty()) { return 0; }
AwardPool pool = FModel.getConquest().getModel().getCurrentPlane().getAwardPool();
ConquestAwardPool pool = FModel.getConquest().getModel().getCurrentPlane().getAwardPool();
//determine average value of filtered cards
int totalValue = 0;

View File

@@ -26,7 +26,6 @@ import forge.itemmanager.ColumnDef;
import forge.itemmanager.ItemColumn;
import forge.itemmanager.ItemManagerConfig;
import forge.model.FModel;
import forge.planarconquest.ConquestPlane.Region;
import forge.planarconquest.ConquestPreferences.CQPref;
import forge.properties.ForgeConstants;
import forge.util.FileUtil;
@@ -36,7 +35,6 @@ import forge.util.XmlWriter;
import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
import java.util.EnumMap;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
@@ -58,7 +56,7 @@ public final class ConquestData {
private final File directory;
private final String xmlFilename;
private final ConquestRecord chaosBattleRecord;
private final EnumMap<ConquestPlane, ConquestPlaneData> planeDataMap = new EnumMap<ConquestPlane, ConquestPlaneData>(ConquestPlane.class);
private final Map<String, ConquestPlaneData> planeDataMap = new HashMap<String, ConquestPlaneData>();
private final HashSet<PaperCard> unlockedCards = new HashSet<PaperCard>();
private final List<ConquestCommander> commanders = new ArrayList<ConquestCommander>();
private final HashSet<PaperCard> newCards = new HashSet<PaperCard>();
@@ -68,7 +66,7 @@ public final class ConquestData {
directory = new File(ForgeConstants.CONQUEST_SAVE_DIR, name);
xmlFilename = directory.getPath() + ForgeConstants.PATH_SEPARATOR + XML_FILE;
aetherShards = FModel.getConquestPreferences().getPrefInt(CQPref.AETHER_START_SHARDS);
currentLocation = new ConquestLocation(startingPlane0, 0, 0, Region.START_COL);
currentLocation = new ConquestLocation(startingPlane0, 0, 0, ConquestRegion.START_COL);
setPlaneswalker(startingPlaneswalker0);
unlockCard(startingPlaneswalker0);
@@ -102,7 +100,7 @@ public final class ConquestData {
xml.read("unlockedCards", unlockedCards, cardDb);
xml.read("newCards", newCards, cardDb);
xml.read("commanders", commanders, ConquestCommander.class);
xml.read("planeDataMap", planeDataMap, ConquestPlane.class, ConquestPlaneData.class);
xml.read("planeDataMap", planeDataMap, ConquestPlaneData.class);
}
catch (Exception e) {
e.printStackTrace();
@@ -149,7 +147,7 @@ public final class ConquestData {
ConquestPlaneData planeData = planeDataMap.get(plane);
if (planeData == null) {
planeData = new ConquestPlaneData(plane);
planeDataMap.put(plane, planeData);
planeDataMap.put(plane.getName(), planeData);
}
return planeData;
}
@@ -221,8 +219,8 @@ public final class ConquestData {
int conquered = 0;
int total = 0;
for (ConquestPlane plane : ConquestPlane.values()) {
ConquestPlaneData planeData = planeDataMap.get(plane);
for (ConquestPlane plane : FModel.getPlanes()) {
ConquestPlaneData planeData = planeDataMap.get(plane.getName());
if (planeData != null) {
conquered += planeData.getConqueredCount();
}
@@ -299,8 +297,8 @@ public final class ConquestData {
private PathFinder() {
ConquestPlane plane = getCurrentPlane();
int xMax = Region.COLS_PER_REGION;
int yMax = plane.getRegions().size() * Region.ROWS_PER_REGION;
int xMax = ConquestRegion.COLS_PER_REGION;
int yMax = plane.getRegions().size() * ConquestRegion.ROWS_PER_REGION;
map = new Node[xMax][yMax];
for (int x = 0; x < xMax; x++) {
for (int y = 0; y < yMax; y++) {
@@ -380,7 +378,7 @@ public final class ConquestData {
private Node getNode(ConquestLocation loc) {
int x = loc.getCol();
int y = loc.getRegionIndex() * Region.ROWS_PER_REGION + loc.getRow();
int y = loc.getRegionIndex() * ConquestRegion.ROWS_PER_REGION + loc.getRow();
return map[x][y];
}
@@ -396,9 +394,9 @@ public final class ConquestData {
x = x0;
y = y0;
int regionIndex = y / Region.ROWS_PER_REGION;
int regionIndex = y / ConquestRegion.ROWS_PER_REGION;
int col = x;
int row = y % Region.ROWS_PER_REGION;
int row = y % ConquestRegion.ROWS_PER_REGION;
loc = new ConquestLocation(plane, regionIndex, row, col);
}

View File

@@ -11,7 +11,6 @@ import forge.interfaces.IGuiGame;
import forge.item.PaperCard;
import forge.model.FModel;
import forge.planarconquest.ConquestEvent.ConquestEventRecord;
import forge.planarconquest.ConquestPlane.Region;
import forge.util.Aggregates;
import forge.util.XmlReader;
import forge.util.XmlWriter;
@@ -31,14 +30,14 @@ public class ConquestLocation implements IXmlWritable {
}
public ConquestLocation(XmlReader xml) {
plane = xml.read("plane", ConquestPlane.Alara);
plane = FModel.getPlanes().get(xml.read("plane", "Alara"));
regionIndex = xml.read("regionIndex", 0);
row = xml.read("row", 0);
col = xml.read("col", 0);
}
@Override
public void saveToXml(XmlWriter xml) {
xml.write("plane", plane);
xml.write("plane", plane.getName());
xml.write("regionIndex", regionIndex);
xml.write("row", row);
xml.write("col", col);
@@ -48,7 +47,7 @@ public class ConquestLocation implements IXmlWritable {
return plane;
}
public Region getRegion() {
public ConquestRegion getRegion() {
if (regionIndex == -1 || regionIndex == plane.getRegions().size()) {
return null; //indicates we're on portal row
}
@@ -83,7 +82,7 @@ public class ConquestLocation implements IXmlWritable {
List<ConquestLocation> locations = new ArrayList<ConquestLocation>();
//add location above
if (row0 < Region.ROWS_PER_REGION - 1) {
if (row0 < ConquestRegion.ROWS_PER_REGION - 1) {
locations.add(new ConquestLocation(plane0, regionIndex0, row0 + 1, col0));
}
else if (regionIndex0 < regionCount - 1) {
@@ -95,7 +94,7 @@ public class ConquestLocation implements IXmlWritable {
locations.add(new ConquestLocation(plane0, regionIndex0, row0 - 1, col0));
}
else if (regionIndex0 > 0) {
locations.add(new ConquestLocation(plane0, regionIndex0 - 1, Region.ROWS_PER_REGION - 1, col0));
locations.add(new ConquestLocation(plane0, regionIndex0 - 1, ConquestRegion.ROWS_PER_REGION - 1, col0));
}
//add location to left
@@ -104,7 +103,7 @@ public class ConquestLocation implements IXmlWritable {
}
//add location to right
if (col0 < Region.COLS_PER_REGION - 1) {
if (col0 < ConquestRegion.COLS_PER_REGION - 1) {
locations.add(new ConquestLocation(plane0, regionIndex0, row0, col0 + 1));
}
@@ -125,7 +124,7 @@ public class ConquestLocation implements IXmlWritable {
//TODO: Make this pull from predefined events
ConquestEventRecord record = FModel.getConquest().getModel().getCurrentPlaneData().getEventRecord(this);
return new ConquestEvent(this, record == null ? 0 : Math.min(record.getHighestConqueredTier() + 1, 3)) {
private final PaperCard commander = Aggregates.random(getRegion().getCommanders());
private final PaperCard commander = Aggregates.random(plane.getCommanders());
@Override
protected Deck buildOpponentDeck() {

View File

@@ -17,381 +17,118 @@
*/
package forge.planarconquest;
import java.util.ArrayList;
import java.util.Collections;
import java.util.EnumSet;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import com.google.common.base.Predicate;
import com.google.common.base.Function;
import forge.GuiBase;
import forge.assets.ISkinImage;
import forge.card.CardDb;
import forge.card.CardEdition;
import forge.card.CardEdition.CardInSet;
import forge.card.CardRules;
import forge.card.ColorSet;
import forge.card.MagicColor;
import forge.deck.generation.DeckGenPool;
import forge.item.PaperCard;
import forge.model.FModel;
import forge.planarconquest.ConquestPreferences.CQPref;
import forge.util.Aggregates;
import forge.properties.ForgeConstants;
import forge.util.FileUtil;
import forge.util.collect.FCollection;
import forge.util.collect.FCollectionView;
import forge.util.storage.StorageBase;
import forge.util.storage.StorageReaderFile;
public enum ConquestPlane {
Alara("Alara", new String[] {
"ALA", "CON", "ARB"
}, new String[] {
"Bant", "Grixis", "Jund", "Naya", "The Maelstrom"
}, new String[] {
"Unstable Obelisk", "Baleful Strix", "Shardless Agent", "Etherium-Horn Sorcerer",
"Patron of the Valiant", "Sublime Archangel", "Naya Soulbeast", "Stalwart Aven",
"Citadel Castellan", "Ajani's Mantra", "Topan Freeblade", "Valeron Wardens",
"Honored Hierarch", "Knight of the Pilgrim's Road", "Relic Seeker", "War Oracle",
"Derevi, Empyrial Tactician", "Kaalia of the Vast", "Bloodspore Thrinax",
"Duskmantle Prowler", "Duty-Bound Dead", "Knight of Glory", "Knight of Infamy",
"Nefarox, Overlord of Grixis", "Servant of Nefarox", "Cathedral of War",
"Meren of Clan Nel Toth", "Jazal Goldmane", "Jhessian Thief", "Maelstrom Wanderer",
"Preyseizer Dragon", "Thromok the Insatiable", "Restore", "Rhox Faithmender",
"Rhox Pikemaster", "Roon of the Hidden Realm", "Scourge of Nel Toth"
}, new Region[] {
new Region("Bant", "Bant Panorama", MagicColor.GREEN | MagicColor.WHITE | MagicColor.BLUE),
new Region("Esper", "Esper Panorama", MagicColor.WHITE | MagicColor.BLUE | MagicColor.BLACK),
new Region("Grixis", "Grixis Panorama", MagicColor.BLUE | MagicColor.BLACK | MagicColor.RED),
new Region("Jund", "Jund Panorama", MagicColor.BLACK | MagicColor.RED | MagicColor.GREEN),
new Region("Naya", "Naya Panorama", MagicColor.RED | MagicColor.GREEN | MagicColor.WHITE),
new Region("Maelstrom", "Rupture Spire", ColorSet.ALL_COLORS.getColor())
}),
Dominaria("Dominaria", new String[] {
"ICE", "ALL", "CSP",
"MIR", "VIS", "WTH",
"USG", "ULG", "UDS",
"INV", "PLS", "APC",
"ODY", "TOR", "JUD",
"ONS", "LGN", "SCG",
"TSP", "PLC", "FUT"
}, new String[] {
"Academy at Tolaria West", "Isle of Vesuva", "Krosa", "Llanowar", "Otaria", "Shiv", "Talon Gates"
}, new String[] {
"Crown of Empires", "Scepter of Empires", "Throne of Empires", "Roc Egg", "Brindle Boar",
"Armored Cancrix", "Academy Raider", "Alaborn Cavalier", "Prossh, Skyraider of Kher",
"Balance of Power", "Beetleback Chief", "Crimson Mage", "Cruel Edict", "Dakmor Lancer",
"Famine", "Firewing Phoenix", "Flesh to Dust", "Flusterstorm", "Freyalise, Llanowar's Fury",
"Gaea's Revenge", "Ice Cage", "Liliana, Heretical Healer", "Mwonvuli Beast Tracker",
"Teferi, Temporal Archmage", "Titania, Protector of Argoth", "Onyx Mage"
}, new Region[] {
new Region("Ice Age", "Dark Depths", inSet("ICE", "ALL", "CSP")),
new Region("Mirage", "Teferi's Isle", inSet("MIR", "VIS", "WTH")),
new Region("Urza's Saga", "Tolarian Academy", inSet("USG", "ULG", "UDS")),
new Region("Invasion", "Legacy Weapon", inSet("INV", "PLS", "APC")),
new Region("Odyssey", "Cabal Coffers", inSet("ODY", "TOR", "JUD")),
new Region("Onslaught", "Grand Coliseum", inSet("ONS", "LGN", "SCG")),
new Region("Time Spiral", "Vesuva", inSet("TSP", "TSB", "PLC", "FUT"))
}),
Innistrad("Innistrad", new String[] {
"ISD", "DKA", "AVR"
}, new String[] {
"Gavony", "Kessig", "Nephalia"
}, new String[] {
"Profane Memento", "Strionic Resonator", "Guardian Seraph", "Seraph of the Sword",
"Soul of Innistrad", "Ajani's Pridemate", "Jeleva, Nephalia's Scourge", "Blood Bairn",
"Blood Host", "Call of the Full Moon", "Captivating Vampire", "Child of Night",
"Jeleva, Nephalia's Scourge", "Vampire Nocturnus", "Crusader of Odric", "Odric, Master Tactician",
"Curse of Chaos", "Curse of Inertia", "Curse of Predation", "Curse of Shallow Graves",
"Curse of the Forsaken", "Deathreap Ritual", "Malicious Affliction", "Predator's Howl",
"Geist of the Moors", "Ghoulcaller Gisa", "Hushwing Gryff", "Possessed Skaab", "Predator's Howl",
"Sign in Blood", "Stitcher Geralf"
}, new Region[] {
new Region("Moorland", "Moorland Haunt", MagicColor.WHITE | MagicColor.BLUE),
new Region("Nephalia", "Nephalia Drownyard", MagicColor.BLUE | MagicColor.BLACK),
new Region("Stensia", "Stensia Bloodhall", MagicColor.BLACK | MagicColor.RED),
new Region("Kessig", "Kessig Wolf Run", MagicColor.RED | MagicColor.GREEN),
new Region("Gavony", "Gavony Township", MagicColor.GREEN | MagicColor.WHITE),
}),
Kaladesh("Kaladesh", new String[] {
}, new String[] {
"Immersturm" //TODO: Replace with proper plane when one created
}, new String[] {
"Consul's Lieutenant"
}, new Region[] {
new Region("", "", ColorSet.ALL_COLORS.getColor())
}),
Kamigawa("Kamigawa", new String[] {
"CHK", "BOK", "SOK"
}, new String[] {
"Minamo", "Orochi Colony", "Sokenzan", "Takenuma"
}, new String[] {
"Champion's Helm", "Haunted Plate Mail", "Sai of the Shinobi", "Kaseto, Orochi Archmage",
"Gahiji, Honored One", "Kurkesh, Onakke Ancient", "Sakashima's Student", "Silent-Blade Oni",
"Vela the Night-Clad"
}, new Region[] {
new Region("Towabara", "Eiganjo Castle", MagicColor.WHITE),
new Region("Minamo Academy", "Minamo, School at Water's Edge", MagicColor.BLUE),
new Region("Takenuma", "Shizo, Death's Storehouse", MagicColor.BLACK),
new Region("Sokenzan Mountains", "Shinka, the Bloodsoaked Keep", MagicColor.RED),
new Region("Jukai Forest", "Okina, Temple to the Grandfathers", MagicColor.GREEN),
}),
LorwynShadowmoor("Lorwyn-Shadowmoor", new String[] {
"LRW", "MOR", "SHM", "EVE"
}, new String[] {
"Goldmeadow", "The Great Forest", "Velis Vel", "Raven's Run",
}, new String[] {
"Throwing Knife", "Awakener Druid", "Boonweaver Giant", "Cruel Sadist", "Dungrove Elder",
"Great Oak Guardian", "Dwynen's Elite", "Dwynen, Gilt-Leaf Daen", "Eyeblight Assassin",
"Eyeblight Massacre", "Flamekin Village", "Fleshpulper Giant", "Gilt-Leaf Winnower",
"Gnarlroot Trapper", "Harbinger of the Tides", "Marath, Will of the Wild", "Shaman of the Pack",
"Thornbow Archer", "Outland Colossus"
}, new Region[] {
new Region("Wanderwine Hub", "Wanderwine Hub", MagicColor.WHITE | MagicColor.BLUE),
new Region("Secluded Glen", "Secluded Glen", MagicColor.BLUE | MagicColor.BLACK),
new Region("Auntie's Hovel", "Auntie's Hovel", MagicColor.BLACK | MagicColor.RED),
new Region("Rustic Clachan", "Rustic Clachan", MagicColor.GREEN | MagicColor.WHITE),
new Region("Gilt-Leaf Palace", "Gilt-Leaf Palace", MagicColor.BLACK | MagicColor.GREEN),
new Region("Ancient Amphitheater", "Ancient Amphitheater", MagicColor.RED | MagicColor.WHITE),
new Region("Murmuring Bosk", "Murmuring Bosk", MagicColor.WHITE | MagicColor.BLACK | MagicColor.GREEN),
new Region("Primal Beyond", "Primal Beyond", ColorSet.ALL_COLORS.getColor())
}),
Mercadia("Mercadia", new String[] {
"MMQ", "NEM", "PCY"
}, new String[] {
"Cliffside Market"
}, new String[] {
}, new Region[] {
new Region("Fountain of Cho", "Fountain of Cho", MagicColor.WHITE),
new Region("Saprazzan Cove", "Saprazzan Cove", MagicColor.BLUE),
new Region("Subterranean Hangar", "Subterranean Hangar", MagicColor.BLACK),
new Region("Mercadian Bazaar", "Mercadian Bazaar", MagicColor.RED),
new Region("Rushwood Grove", "Rushwood Grove", MagicColor.GREEN)
}),
Mirrodin("Mirrodin", new String[] {
"MRD", "DST", "5DN", "SOM", "MBS", "NPH"
}, new String[] {
"Panopticon", "Quicksilver Sea", "Furnace Layer", "Norn's Dominion"
}, new String[] {
"Crystal Ball", "Vial of Poison", "Avarice Amulet", "Masterwork of Ingenuity", "Scytheclaw",
"Soul of New Phyrexia", "Adaptive Automaton", "Bonded Construct", "Chief of the Foundry",
"Guardian Automaton", "Hangarback Walker", "Scuttling Doom Engine", "Steel Overseer",
"Chronomaton", "Ramroller", "Augury Owl", "Healer of the Pride", "Aeronaut Tinkerer",
"Aspiring Aeronaut", "Foundry of the Consuls", "Ghirapur Gearcrafter", "Pia and Kiran Nalaar",
"Thopter Engineer", "Thopter Spy Network", "Whirler Rogue", "Ajani, Caller of the Pride",
"Blastfire Bolt", "Buried Ruin", "Chief Engineer", "Artificer's Hex", "Artificer's Epiphany",
"Feldon of the Third Path", "Flamewright", "Muzzio, Visionary Architect", "Reclusive Artificer",
"Sydri, Galvanic Genius", "Darksteel Mutation", "Ensoul Artifact", "Ezuri, Claw of Progress",
"Ghirapur AEther Grid", "Hoarding Dragon", "Manic Vandal", "Molten Birth", "Phylactery Lich",
"Preordain", "Scrap Mastery", "Scrapyard Mongrel", "Smelt"
}, new Region[] {
new Region("Panopticon", "Darksteel Citadel", MagicColor.COLORLESS),
new Region("Taj-Nar", "Ancient Den", MagicColor.WHITE),
new Region("Lumengrid", "Seat of the Synod", MagicColor.BLUE),
new Region("Ish Sah", "Vault of Whispers", MagicColor.BLACK),
new Region("Kuldotha", "Great Furnace", MagicColor.RED),
new Region("Tel-Jilad", "Tree of Tales", MagicColor.GREEN),
new Region("Glimmervoid", "Glimmervoid", ColorSet.ALL_COLORS.getColor())
}),
Rath("Rath", new String[] {
"TMP", "STH", "EXO"
}, new String[] {
"Stronghold Furnace"
}, new String[] {
"Battle Sliver", "Belligerent Sliver", "Blur Sliver", "Bonescythe Sliver", "Constricting Sliver",
"Diffusion Sliver", "Galerider Sliver", "Groundshaker Sliver", "Hive Stirrings", "Leeching Sliver",
"Manaweft Sliver", "Megantic Sliver", "Predatory Sliver", "Sentinel Sliver", "Sliver Construct",
"Sliver Hive", "Sliver Hivelord", "Steelform Sliver", "Striking Sliver", "Syphon Sliver",
"Thorncaster Sliver", "Venom Sliver"
}, new Region[] {
new Region("Caldera Lake", "Caldera Lake", MagicColor.BLUE | MagicColor.RED),
new Region("Cinder Marsh", "Cinder Marsh", MagicColor.BLACK | MagicColor.RED),
new Region("Mogg Hollows", "Mogg Hollows", MagicColor.RED | MagicColor.GREEN),
new Region("Pine Barrens", "Pine Barrens", MagicColor.BLACK | MagicColor.GREEN),
new Region("Rootwater Depths", "Rootwater Depths", MagicColor.BLUE | MagicColor.BLACK),
new Region("Salt Flats", "Salt Flats", MagicColor.WHITE | MagicColor.BLACK),
new Region("Scabland", "Scabland", MagicColor.RED | MagicColor.WHITE),
new Region("Skyshroud Forest", "Skyshroud Forest", MagicColor.GREEN | MagicColor.BLUE),
new Region("Thalakos Lowlands", "Thalakos Lowlands", MagicColor.WHITE | MagicColor.BLUE),
new Region("Vec Townships", "Vec Townships", MagicColor.GREEN | MagicColor.WHITE)
}),
Ravnica("Ravnica", new String[] {
"RAV", "GPT", "DIS", "RTR", "GTC", "DGM"
}, new String[] {
"Agyrem", "Grand Ossuary", "Izzet Steam Maze", "Orzhova", "Prahv", "Selesnya Loft Gardens", "Undercity Reaches"
}, new String[] {
"Druidic Satchel", "Gem of Becoming", "Obelisk of Urd", "Will-Forged Golem", "Seraph of the Masses",
"Avatar of Slaughter", "Basandra, Battle Seraph", "Soul of Ravnica", "Duskhunter Bat",
"Shattergang Brothers", "Blood Ogre", "Bloodlord of Vaasgoth", "Bloodrage Vampire", "Carnage Wurm",
"Furyborn Hellkite", "Gorehorn Minotaurs", "Lurking Crocodile", "Stormblood Berserker",
"Vampire Outcasts", "Bounding Krasis", "Conclave Naturalists", "Covenant of Blood",
"Crowd's Favor", "Endless Obedience", "Ephemeral Shields", "Feral Incarnation", "Living Totem",
"Meditation Puzzle", "Return to the Ranks", "Stain the Mind", "Stoke the Flames", "Triplicate Spirits",
"Unmake the Graves", "Deadbridge Shaman", "Extract from Darkness", "Mizzium Meddler", "Mizzix of the Izmagnus",
"Karlov of the Ghost Council", "Mazirek, Kraul Death Priest", "Fungal Sprouting", "Ghave, Guru of Spores",
"Jade Mage", "Sporemound", "Jace, the Living Guildpact", "Krenko's Command", "Krenko's Enforcer", "Krenko, Mob Boss",
"Leyline of Anticipation", "Leyline of Punishment", "Leyline of Sanctity", "Leyline of Vitality", "Mantle of Webs",
"Nightsnare", "Shattergang Brothers", "Yeva's Forcemage", "Yeva, Nature's Herald", "Rhox Maulers",
"Goblin Glory Chaser", "Scab-Clan Berserker", "Undercity Troll"
}, new Region[] {
new Region("Azorius Chancery", "Azorius Chancery", MagicColor.WHITE | MagicColor.BLUE),
new Region("Boros Garrison", "Boros Garrison", MagicColor.RED | MagicColor.WHITE),
new Region("Dimir Aqueduct", "Dimir Aqueduct", MagicColor.BLUE | MagicColor.BLACK),
new Region("Golgari Rot Farm", "Golgari Rot Farm", MagicColor.BLACK | MagicColor.GREEN),
new Region("Gruul Turf", "Gruul Turf", MagicColor.RED | MagicColor.GREEN),
new Region("Izzet Boilerworks", "Izzet Boilerworks", MagicColor.BLUE | MagicColor.RED),
new Region("Orzhov Basilica", "Orzhov Basilica", MagicColor.WHITE | MagicColor.BLACK),
new Region("Rakdos Carnarium", "Rakdos Carnarium", MagicColor.BLACK | MagicColor.RED),
new Region("Selesnya Sanctuary", "Selesnya Sanctuary", MagicColor.GREEN | MagicColor.WHITE),
new Region("Simic Growth Chamber", "Simic Growth Chamber", MagicColor.GREEN | MagicColor.BLUE)
}),
Regatha("Regatha", new String[] {
}, new String[] {
"Mount Keralia"
}, new String[] {
"Firefiend Elemental", "Acolyte of the Inferno"
}, new Region[] {
new Region("", "", ColorSet.ALL_COLORS.getColor())
}),
Shandalar("Shandalar", new String[] {
"2ED", "3ED", "4ED", "ARN", "ATQ", "LEG", "DRK", "FEM"
}, new String[] {
"Eloren Wilds", "Onakke Catacomb"
}, new String[] {
"Acorn Catapult", "Tyrant's Machine", "Brittle Effigy", "Kird Chieftain", "Soul of Shandalar",
"Ring of Evos Isle", "Ring of Kalonia", "Ring of Thune", "Ring of Valkas", "Ring of Xathrid",
"Kalonian Behemoth", "Kalonian Tusker", "Kalonian Hydra", "Kalonian Twingrove", "Roaring Primadox",
"Thragtusk", "Warden of Evos Isle", "Initiates of the Ebon Hand", "Deathgaze Cockatrice",
"Acolyte of Xathrid", "Xathrid Demon", "Xathrid Gorgon", "Xathrid Necromancer", "Xathrid Slyblade",
"Downpour", "Talrand's Invocation", "Talrand, Sky Summoner", "Encrust", "Sentinel Spider",
"Faith's Reward", "Garruk, Apex Predator", "Garruk, Primal Hunter", "Griffin Rider",
"Hunter's Insight", "In Garruk's Wake", "Jalira, Master Polymorphist", "Kothophed, Soul Hoarder",
"Magmatic Force", "Master of the Pearl Trident", "Polymorphist's Jest", "Scroll Thief",
"The Chain Veil", "Yisan, the Wanderer Bard"
}, new Region[] {
new Region("Core", "Black Lotus", inSet("2ED", "3ED", "4ED")),
new Region("Arabian Nights", "Library of Alexandria", inSet("ARN")),
new Region("Antiquities", "Mishra's Workshop", inSet("ATQ")),
new Region("Legends", "Karakas", inSet("LEG")),
new Region("The Dark", "City of Shadows", inSet("DRK")),
new Region("Fallen Empires", "Ruins of Trokair", inSet("FEM"))
}),
Tarkir("Tarkir", new String[] {
"KTK", "FRF", "DTK"
}, new String[] {
"Kharasha Foothills"
}, new String[] {
"Ringwarden Owl", "Aven Battle Priest", "Abbot of Keral Keep", "Mage-Ring Bully"
}, new Region[] {
new Region("Abzan Houses", "Sandsteppe Citadel", MagicColor.WHITE | MagicColor.BLACK | MagicColor.GREEN),
new Region("Jeskai Way", "Mystic Monastery", MagicColor.BLUE | MagicColor.RED | MagicColor.WHITE),
new Region("Mardu Horde", "Nomad Outpost", MagicColor.RED | MagicColor.WHITE | MagicColor.BLACK),
new Region("Sultai Brood", "Opulent Palace", MagicColor.BLACK | MagicColor.GREEN | MagicColor.BLUE),
new Region("Temur Frontier", "Frontier Bivouac", MagicColor.GREEN | MagicColor.BLUE | MagicColor.RED)
}),
Theros("Theros", new String[] {
"THS", "BNG", "JOU"
}, new String[] {
"Lethe Lake"
}, new String[] {
"Gorgon Flail", "Helm of the Gods", "Sigil of Valor", "Aegis Angel", "Soul of Theros",
"Enlightened Ascetic", "Ajani's Chosen", "Herald of the Pantheon", "Ajani Steadfast",
"Ajani's Sunstriker", "Akroan Jailer", "Akroan Sergeant", "Anchor to the AEther",
"Blood-Cursed Knight", "Daxos the Returned", "Daxos's Torment", "Kalemne, Disciple of Iroas",
"Gideon's Avenger", "Gideon's Lawkeeper", "Gideon's Phalanx", "Grasp of the Hieromancer",
"Kytheon's Irregulars", "Kytheon's Tactics", "Kytheon, Hero of Akros", "Hixus, Prison Warden",
"Iroas's Champion", "Kalemne's Captain", "Magmatic Insight", "Oath of the Ancient Wood",
"Prickleboar", "Shadows of the Past", "Starfield of Nyx", "Suppression Bonds", "Valor in Akros",
"Pharika's Disciple", "Celestial Flare"
}, new Region[] {
new Region("Oreskos", "Temple of Plenty", MagicColor.WHITE),
new Region("Meletis", "Temple of Enlightenment", MagicColor.BLUE),
new Region("Asphodel", "Temple of Silence", MagicColor.BLACK),
new Region("Akros", "Temple of Malice", MagicColor.RED),
new Region("Setessa", "Temple of Mystery", MagicColor.GREEN),
}),
Ulgrotha("Ulgrotha", new String[] {
"HML"
}, new String[] {
"The Dark Barony"
}, new String[] {
"Elixir of Immortality", "Viscera Seer"
}, new Region[] {
new Region("", "", inSet("HML"))
}),
Zendikar("Zendikar", new String[] {
"ZEN", "WWK", "ROE", "BFZ", "OGW"
}, new String[] {
"Akoum", "Hedron Fields of Agadeem", "Murasa", "Tazeem"
}, new String[] {
"Perilous Vault", "Archangel of Thune", "Soul of Zendikar", "Boundless Realms", "Malakir Cullblade",
"Nissa's Expedition", "Dismiss into Dream", "Elemental Bond", "Elvish Archdruid", "Elvish Mystic",
"Nahiri, the Lithomancer", "Felidar Umbra", "Indrik Umbra", "Into the Wilds", "Joraga Invocation",
"Mind Control", "Nissa's Pilgrimage", "Nissa's Revelation", "Nissa, Vastwood Seer", "Nissa, Worldwaker",
"Ob Nixilis of the Black Oath", "Ob Nixilis, Unshackled", "Sword of the Animist", "Vastwood Hydra",
"Wild Instincts", "Woodborn Behemoth", "Zendikar Incarnate", "Zendikar's Roil"
}, new Region[] {
new Region("Kazandu", "Kazandu Refuge", MagicColor.RED | MagicColor.GREEN),
new Region("Graypelt", "Graypelt Refuge", MagicColor.GREEN | MagicColor.WHITE),
new Region("Sejiri", "Sejiri Refuge", MagicColor.WHITE | MagicColor.BLUE),
new Region("Jwar Isle", "Jwar Isle Refuge", MagicColor.BLUE | MagicColor.BLACK),
new Region("Akoum", "Akoum Refuge", MagicColor.BLACK | MagicColor.RED),
new Region("Blind Eternities", "Eldrazi Temple", MagicColor.COLORLESS)
});
public class ConquestPlane {
private final String name;
private final FCollection<CardEdition> editions = new FCollection<CardEdition>();
private final FCollection<Region> regions;
private final FCollection<String> bannedCards = new FCollection<String>();
private final DeckGenPool cardPool = new DeckGenPool();
private final FCollection<PaperCard> planeCards = new FCollection<PaperCard>();
private final FCollection<PaperCard> commanders = new FCollection<PaperCard>();
private AwardPool awardPool;
private final String directory;
private FCollection<ConquestRegion> regions;
private DeckGenPool cardPool;
private FCollection<PaperCard> planeCards;
private FCollection<PaperCard> commanders;
private ConquestAwardPool awardPool;
private ConquestPlane(String name0, String[] setCodes0, String[] planeCards0, String[] additionalCards0, Region[] regions0) {
this(name0, setCodes0, planeCards0, additionalCards0, regions0, null);
}
private ConquestPlane(String name0, String[] setCodes0, String[] planeCards0, String[] additionalCards0, Region[] regions0, String[] bannedCards0) {
private ConquestPlane(String name0) {
name = name0;
regions = new FCollection<Region>(regions0);
if (bannedCards0 != null) {
bannedCards.addAll(bannedCards0);
}
directory = ForgeConstants.CONQUEST_PLANES_DIR + name + ForgeConstants.PATH_SEPARATOR;
}
for (Region region : regions) {
region.plane = this;
public String getName() {
return name;
}
public String getDirectory() {
return directory;
}
public FCollectionView<ConquestRegion> getRegions() {
ensureRegionsLoaded();
return regions;
}
public int getEventCount() {
ensureRegionsLoaded();
return regions.size() * ConquestRegion.ROWS_PER_REGION * ConquestRegion.COLS_PER_REGION;
}
public DeckGenPool getCardPool() {
ensureRegionsLoaded();
return cardPool;
}
public FCollectionView<PaperCard> getCommanders() {
ensureRegionsLoaded();
return commanders;
}
public FCollectionView<PaperCard> getPlaneCards() {
if (planeCards == null) {
planeCards = new FCollection<PaperCard>();
CardDb variantCards = FModel.getMagicDb().getVariantCards();
List<String> planeCardNames = FileUtil.readFile(directory + "plane_cards.txt");
for (String name : planeCardNames) {
PaperCard pc = variantCards.getCard(name);
if (pc == null) {
System.out.println("\"" + name + "\" does not correspond to a valid Plane card");
continue;
}
planeCards.add(pc);
}
}
return planeCards;
}
private void ensureRegionsLoaded() {
if (regions != null) { return; }
regions = new FCollection<ConquestRegion>(new StorageBase<ConquestRegion>("Conquest regions", new ConquestRegion.Reader(this)));
//must initialize card pool when regions loaded
cardPool = new DeckGenPool();
commanders = new FCollection<PaperCard>();
CardDb commonCards = FModel.getMagicDb().getCommonCards();
for (String setCode : setCodes0) {
List<String> bannedCards = FileUtil.readFile(directory + "banned_cards.txt");
Set<String> bannedCardSet = bannedCards.isEmpty() ? null : new HashSet<String>(bannedCards);
List<String> setCodes = FileUtil.readFile(directory + "sets.txt");
for (String setCode : setCodes) {
CardEdition edition = FModel.getMagicDb().getEditions().get(setCode);
if (edition != null) {
editions.add(edition);
for (CardInSet card : edition.getCards()) {
if (!bannedCards.contains(card.name)) {
if (bannedCardSet == null || !bannedCardSet.contains(card.name)) {
addCard(commonCards.getCard(card.name, setCode));
}
}
}
}
for (String cardName : additionalCards0) {
List<String> additionalCards = FileUtil.readFile(directory + "cards.txt");
for (String cardName : additionalCards) {
addCard(commonCards.getCard(cardName));
}
CardDb variantCards = FModel.getMagicDb().getVariantCards();
for (String planeCard : planeCards0) {
PaperCard pc = variantCards.getCard(planeCard);
if (pc == null) {
System.out.println("\"" + planeCard + "\" does not correspond to a valid Plane card");
continue;
}
planeCards.add(pc);
}
//sort commanders by name
Collections.sort(commanders);
}
@@ -400,291 +137,53 @@ public enum ConquestPlane {
if (pc == null) { return; }
CardRules rules = pc.getRules();
boolean isCommander = pc.getRules().canBeCommander();
if (rules.getType().isBasicLand()) { return; } //ignore basic lands
cardPool.add(pc);
if (isCommander) {
if (rules.canBeCommander()) {
commanders.add(pc);
}
int count = 0;
if (!rules.getType().isBasicLand()) { //add all basic lands to all regions below
for (Region region : regions) {
if (region.pred.apply(pc)) {
region.cardPool.add(pc);
if (isCommander) {
region.commanders.add(pc);
}
count++;
}
}
}
//if card doesn't match any region's predicate,
//make card available to all regions
if (count == 0) {
for (Region region : regions) {
region.cardPool.add(pc);
if (isCommander) {
region.commanders.add(pc);
}
}
}
}
public String getName() {
return name;
}
public FCollectionView<CardEdition> getEditions() {
return editions;
}
public FCollectionView<String> getBannedCards() {
return bannedCards;
}
public FCollectionView<Region> getRegions() {
return regions;
}
public DeckGenPool getCardPool() {
return cardPool;
}
public FCollectionView<PaperCard> getCommanders() {
return commanders;
}
public FCollectionView<PaperCard> getPlaneCards() {
return planeCards;
}
public int getEventCount() {
return regions.size() * Region.ROWS_PER_REGION * Region.COLS_PER_REGION;
ConquestRegion.addCard(pc, regions);
}
public String toString() {
return name;
}
public static class Region {
public static final int ROWS_PER_REGION = 3;
public static final int COLS_PER_REGION = 3;
public static final int START_COL = (COLS_PER_REGION - 1) / 2;
private final String name, artCardName;
private final ColorSet colorSet;
private final Predicate<PaperCard> pred;
private final DeckGenPool cardPool = new DeckGenPool();
private final FCollection<PaperCard> commanders = new FCollection<PaperCard>();
private ConquestPlane plane;
private ISkinImage art;
private Region(String name0, String artCardName0, final int colorMask) {
name = name0;
artCardName = artCardName0;
pred = new Predicate<PaperCard>() {
@Override
public boolean apply(PaperCard pc) {
return pc.getRules().getColorIdentity().hasNoColorsExcept(colorMask);
}
};
colorSet = ColorSet.fromMask(colorMask);
}
private Region(String name0, String artCardName0, Predicate<PaperCard> pred0) {
name = name0;
artCardName = artCardName0;
pred = pred0;
colorSet = ColorSet.fromMask(ColorSet.ALL_COLORS.getColor());
public static final Function<ConquestPlane, String> FN_GET_NAME = new Function<ConquestPlane, String>() {
@Override
public String apply(ConquestPlane plane) {
return plane.getName();
}
};
public String getName() {
return name;
}
public ISkinImage getArt() {
if (art == null) {
art = GuiBase.getInterface().getCardArt(cardPool.getCard(artCardName));
}
return art;
}
public ColorSet getColorSet() {
return colorSet;
}
public DeckGenPool getCardPool() {
return cardPool;
}
public FCollectionView<PaperCard> getCommanders() {
return commanders;
}
public ConquestPlane getPlane() {
return plane;
}
public String toString() {
return plane.name + " - " + name;
}
}
private static Predicate<PaperCard> inSet(final String... sets) {
return new Predicate<PaperCard>() {
@Override
public boolean apply(PaperCard pc) {
for (String set : sets) {
if (pc.getEdition().equals(set)) {
return true;
}
}
return false;
}
};
}
public AwardPool getAwardPool() {
public ConquestAwardPool getAwardPool() {
if (awardPool == null) { //delay initializing until needed
awardPool = new AwardPool(cardPool.getAllCards());
awardPool = new ConquestAwardPool(cardPool.getAllCards());
}
return awardPool;
}
public static class AwardPool {
private final BoosterPool commons, uncommons, rares, mythics;
private final int commonValue, uncommonValue, rareValue, mythicValue;
public AwardPool(Iterable<PaperCard> cards) {
ConquestPreferences prefs = FModel.getConquestPreferences();
commons = new BoosterPool();
uncommons = new BoosterPool();
rares = new BoosterPool();
mythics = new BoosterPool();
for (PaperCard c : cards) {
switch (c.getRarity()) {
case Common:
commons.add(c);
break;
case Uncommon:
uncommons.add(c);
break;
case Rare:
case Special: //lump special cards in with rares for simplicity
rares.add(c);
break;
case MythicRare:
mythics.add(c);
break;
default:
break;
}
}
//calculate odds of each rarity
float commonOdds = commons.getOdds(prefs.getPrefInt(CQPref.BOOSTER_COMMONS));
float uncommonOdds = uncommons.getOdds(prefs.getPrefInt(CQPref.BOOSTER_UNCOMMONS));
int raresPerBooster = prefs.getPrefInt(CQPref.BOOSTER_RARES);
float rareOdds = rares.getOdds(raresPerBooster);
float mythicOdds = mythics.getOdds((float)raresPerBooster / (float)prefs.getPrefInt(CQPref.BOOSTERS_PER_MYTHIC));
//determine value of each rarity based on the base value of a common
commonValue = prefs.getPrefInt(CQPref.AETHER_BASE_VALUE);
uncommonValue = Math.round(commonValue / (uncommonOdds / commonOdds));
rareValue = Math.round(commonValue / (rareOdds / commonOdds));
mythicValue = mythics.isEmpty() ? 0 : Math.round(commonValue / (mythicOdds / commonOdds));
public static class Reader extends StorageReaderFile<ConquestPlane> {
public Reader(String file0) {
super(file0, ConquestPlane.FN_GET_NAME);
}
public int getShardValue(PaperCard card) {
switch (card.getRarity()) {
case Common:
return commonValue;
case Uncommon:
return uncommonValue;
case Rare:
case Special:
return rareValue;
case MythicRare:
return mythicValue;
default:
return 0;
}
}
public BoosterPool getCommons() {
return commons;
}
public BoosterPool getUncommons() {
return uncommons;
}
public BoosterPool getRares() {
return rares;
}
public BoosterPool getMythics() {
return mythics;
}
public class BoosterPool {
private final List<PaperCard> cards = new ArrayList<PaperCard>();
private BoosterPool() {
}
public boolean isEmpty() {
return cards.isEmpty();
}
private float getOdds(float perBoosterCount) {
int count = cards.size();
if (count == 0) { return 0; }
return (float)perBoosterCount / (float)count;
}
private void add(PaperCard c) {
cards.add(c);
}
public void rewardCard(List<PaperCard> rewards) {
int index = Aggregates.randomInt(0, cards.size() - 1);
PaperCard c = cards.get(index);
cards.remove(index);
rewards.add(c);
}
@Override
protected ConquestPlane read(String line, int i) {
return new ConquestPlane(line);
}
}
public static Set<ConquestPlane> getAllPlanesOfCard(PaperCard card) {
EnumSet<ConquestPlane> planes = EnumSet.noneOf(ConquestPlane.class);
for (ConquestPlane plane : values()) {
Set<ConquestPlane> planes = new HashSet<ConquestPlane>();
for (ConquestPlane plane : FModel.getPlanes()) {
if (plane.cardPool.contains(card)) {
planes.add(plane);
}
}
return planes;
}
public static Set<Region> getAllRegionsOfCard(PaperCard card) {
Set<Region> regions = new HashSet<Region>();
for (ConquestPlane plane : values()) {
if (plane.cardPool.contains(card)) {
for (Region region : plane.getRegions()) {
if (region.cardPool.contains(card)) {
regions.add(region);
}
}
}
}
return regions;
}
public static List<Region> getAllRegions() {
List<Region> regions = new ArrayList<Region>();
for (ConquestPlane plane : values()) {
for (Region region : plane.getRegions()) {
regions.add(region);
}
}
return regions;
}
}

View File

@@ -3,7 +3,6 @@ package forge.planarconquest;
import forge.item.PaperCard;
import forge.model.FModel;
import forge.planarconquest.ConquestEvent.ConquestEventRecord;
import forge.planarconquest.ConquestPlane.Region;
import forge.util.XmlReader;
import forge.util.XmlWriter;
import forge.util.XmlWriter.IXmlWritable;
@@ -32,7 +31,7 @@ public class ConquestPlaneData implements IXmlWritable {
return hasConquered(loc.getRegionIndex(), loc.getRow(), loc.getCol());
}
public boolean hasConquered(int regionIndex, int row, int col) {
return hasConquered(regionIndex * Region.ROWS_PER_REGION * Region.COLS_PER_REGION + row * Region.COLS_PER_REGION + col);
return hasConquered(regionIndex * ConquestRegion.ROWS_PER_REGION * ConquestRegion.COLS_PER_REGION + row * ConquestRegion.COLS_PER_REGION + col);
}
private boolean hasConquered(int index) {
ConquestEventRecord result = eventResults[index];
@@ -43,12 +42,12 @@ public class ConquestPlaneData implements IXmlWritable {
return getEventRecord(loc.getRegionIndex(), loc.getRow(), loc.getCol());
}
public ConquestEventRecord getEventRecord(int regionIndex, int row, int col) {
return eventResults[regionIndex * Region.ROWS_PER_REGION * Region.COLS_PER_REGION + row * Region.COLS_PER_REGION + col];
return eventResults[regionIndex * ConquestRegion.ROWS_PER_REGION * ConquestRegion.COLS_PER_REGION + row * ConquestRegion.COLS_PER_REGION + col];
}
private ConquestEventRecord getOrCreateResult(ConquestEvent event) {
ConquestLocation loc = event.getLocation();
int index = loc.getRegionIndex() * Region.ROWS_PER_REGION * Region.COLS_PER_REGION + loc.getRow() * Region.COLS_PER_REGION + loc.getCol();
int index = loc.getRegionIndex() * ConquestRegion.ROWS_PER_REGION * ConquestRegion.COLS_PER_REGION + loc.getRow() * ConquestRegion.COLS_PER_REGION + loc.getCol();
ConquestEventRecord result = eventResults[index];
if (result == null) {
result = new ConquestEventRecord();

View File

@@ -0,0 +1,174 @@
package forge.planarconquest;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import com.google.common.base.Function;
import com.google.common.base.Predicate;
import forge.GuiBase;
import forge.assets.ISkinImage;
import forge.card.ColorSet;
import forge.deck.generation.DeckGenPool;
import forge.item.PaperCard;
import forge.model.FModel;
import forge.util.storage.StorageReaderFile;
public class ConquestRegion {
public static final int ROWS_PER_REGION = 3;
public static final int COLS_PER_REGION = 3;
public static final int START_COL = (COLS_PER_REGION - 1) / 2;
private final ConquestPlane plane;
private final String name, artCardName;
private final ColorSet colorSet;
private final Predicate<PaperCard> pred;
private final DeckGenPool cardPool = new DeckGenPool();
private ISkinImage art;
private ConquestRegion(ConquestPlane plane0, String name0, String artCardName0, ColorSet colorSet0, Predicate<PaperCard> pred0) {
plane = plane0;
name = name0;
artCardName = artCardName0;
pred = pred0;
colorSet = colorSet0;
}
public ConquestPlane getPlane() {
return plane;
}
public String getName() {
return name;
}
public ISkinImage getArt() {
if (art == null) {
art = GuiBase.getInterface().getCardArt(cardPool.getCard(artCardName));
}
return art;
}
public ColorSet getColorSet() {
return colorSet;
}
public DeckGenPool getCardPool() {
return cardPool;
}
public String toString() {
return plane.getName() + " - " + name;
}
public static final Function<ConquestRegion, String> FN_GET_NAME = new Function<ConquestRegion, String>() {
@Override
public String apply(ConquestRegion region) {
return region.getName();
}
};
public static class Reader extends StorageReaderFile<ConquestRegion> {
private final ConquestPlane plane;
public Reader(ConquestPlane plane0) {
super(plane0.getDirectory() + "regions.txt", ConquestRegion.FN_GET_NAME);
plane = plane0;
}
@Override
protected ConquestRegion read(String line, int index) {
String name = null;
String artCardName = null;
ColorSet colorSet = ColorSet.ALL_COLORS;
Predicate<PaperCard> pred = null;
String[] pieces = line.trim().split("\\|");
for (String piece : pieces) {
String[] kv = piece.split(":", 2);
String key = kv[0].trim().toLowerCase();
String value = kv[1].trim();
switch(key) {
case "name":
name = value;
break;
case "art":
artCardName = value;
break;
case "colors":
colorSet = ColorSet.fromNames(value.toCharArray());
final int colorMask = colorSet.getColor();
pred = new Predicate<PaperCard>() {
@Override
public boolean apply(PaperCard pc) {
return pc.getRules().getColorIdentity().hasNoColorsExcept(colorMask);
}
};
break;
case "sets":
final String[] sets = value.split(",");
for (int i = 0; i < sets.length; i++) {
sets[i] = sets[i].trim();
}
pred = new Predicate<PaperCard>() {
@Override
public boolean apply(PaperCard pc) {
for (String set : sets) {
if (pc.getEdition().equals(set)) {
return true;
}
}
return false;
}
};
break;
}
}
return new ConquestRegion(plane, name, artCardName, colorSet, pred);
}
}
static void addCard(PaperCard pc, Iterable<ConquestRegion> regions) {
boolean foundRegion = false;
for (ConquestRegion region : regions) {
if (region.pred.apply(pc)) {
region.cardPool.add(pc);
foundRegion = true;
}
}
if (foundRegion) { return; }
//if card doesn't match any region's predicate, make card available to all regions
for (ConquestRegion region : regions) {
region.cardPool.add(pc);
}
}
public static Set<ConquestRegion> getAllRegionsOfCard(PaperCard card) {
Set<ConquestRegion> regions = new HashSet<ConquestRegion>();
for (ConquestPlane plane : FModel.getPlanes()) {
if (plane.getCardPool().contains(card)) {
for (ConquestRegion region : plane.getRegions()) {
if (region.getCardPool().contains(card)) {
regions.add(region);
}
}
}
}
return regions;
}
public static List<ConquestRegion> getAllRegions() {
List<ConquestRegion> regions = new ArrayList<ConquestRegion>();
for (ConquestPlane plane : FModel.getPlanes()) {
for (ConquestRegion region : plane.getRegions()) {
regions.add(region);
}
}
return regions;
}
}

View File

@@ -73,6 +73,9 @@ public final class ForgeConstants {
public static final String DEFAULT_CHALLENGES_DIR = QUEST_DIR + "challenges";
public static final String THEMES_DIR = QUEST_DIR + "themes";
private static final String CONQUEST_DIR = RES_DIR + "conquest" + PATH_SEPARATOR;
public static final String CONQUEST_PLANES_DIR = CONQUEST_DIR + "planes" + PATH_SEPARATOR;
public static final String SKINS_DIR = RES_DIR + "skins" + PATH_SEPARATOR;
public static final String DEFAULT_SKINS_DIR = SKINS_DIR + "default" + PATH_SEPARATOR;
//don't associate these skin files with a directory since skin directory will be determined later

View File

@@ -99,7 +99,6 @@ public class QuestWorld implements Comparable<QuestWorld>{
}
public static final Function<QuestWorld, String> FN_GET_NAME = new Function<QuestWorld, String>() {
@Override
public String apply(QuestWorld arg1) {
return arg1.getName();

View File

@@ -3,6 +3,7 @@ package forge.util;
import java.io.File;
import java.util.Collection;
import java.util.EnumMap;
import java.util.Map;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
@@ -102,6 +103,30 @@ public class XmlReader {
}
});
}
public <V extends IXmlWritable> void read(final String key, final Map<String, V> enumMap, final Class<V> valueType) {
parseChildElements(key, new Evaluator<Void>() {
@Override
public Void evaluate() {
final GenericBuilder<V> builder = new GenericBuilder<V>(valueType);
return parseChildElements(null, new Evaluator<Void>() {
@Override
public Void evaluate() {
try {
String key = currentElement.getTagName();
V value = builder.evaluate();
if (value != null) {
enumMap.put(key, value);
}
}
catch (Exception e) {
e.printStackTrace();
}
return null;
}
});
}
});
}
public <E extends Enum<E>, V extends IXmlWritable> void read(final String key, final EnumMap<E, V> enumMap, final Class<E> enumType, final Class<V> valueType) {
parseChildElements(key, new Evaluator<Void>() {
@Override

View File

@@ -2,6 +2,7 @@ package forge.util;
import java.util.EnumMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Stack;
@@ -92,6 +93,13 @@ public class XmlWriter {
}
endElement();
}
public void write(String key, Map<String, ? extends IXmlWritable> value) {
startElement(key);
for (Entry<String, ? extends IXmlWritable> entry : value.entrySet()) {
write(entry.getKey(), entry.getValue());
}
endElement();
}
public void write(String key, EnumMap<? extends Enum<?>, ? extends IXmlWritable> value) {
startElement(key);
for (Entry<? extends Enum<?>, ? extends IXmlWritable> entry : value.entrySet()) {