Refactor conquest AEther reward structure and filters

This commit is contained in:
drdev
2016-03-19 22:52:30 +00:00
parent ac4c7fd83d
commit 50172a3be6
9 changed files with 171 additions and 104 deletions

View File

@@ -22,7 +22,6 @@ import forge.assets.FSkinImage;
import forge.card.mana.ManaCost;
import forge.card.mana.ManaCostShard;
import forge.error.BugReporter;
import java.util.HashMap;
import java.util.Map;
import java.util.StringTokenizer;

View File

@@ -16,15 +16,21 @@ import forge.animation.ForgeAnimation;
import forge.assets.FSkin;
import forge.assets.FSkinColor;
import forge.assets.FSkinFont;
import forge.assets.FSkinProp;
import forge.assets.FSkinTexture;
import forge.assets.TextRenderer;
import forge.card.CardRenderer;
import forge.card.CardZoom;
import forge.card.ColorSet;
import forge.card.CardRenderer.CardStackPosition;
import forge.card.ColorSetImage;
import forge.item.PaperCard;
import forge.model.FModel;
import forge.planarconquest.ConquestAwardPool;
import forge.planarconquest.ConquestCommander;
import forge.planarconquest.ConquestData;
import forge.planarconquest.ConquestPlane;
import forge.planarconquest.ConquestPreferences.CQPref;
import forge.planarconquest.ConquestUtil;
import forge.planarconquest.ConquestUtil.AEtherFilter;
import forge.screens.FScreen;
@@ -59,6 +65,7 @@ public class ConquestAEtherScreen extends FScreen {
private PullAnimation activePullAnimation;
private int shardCost;
private ConquestCommander commander;
public ConquestAEtherScreen() {
super("", ConquestMenu.getMenu());
@@ -71,6 +78,12 @@ public class ConquestAEtherScreen extends FScreen {
setHeaderCaption(model.getName());
ConquestCommander commander0 = model.getSelectedCommander();
if (commander != commander0) {
commander = commander0;
resetFilters(); //reset filters if commander changed since the last time this screen was opened
}
pool.clear();
for (PaperCard card : plane.getCardPool().getAllCards()) {
if (!model.hasUnlockedCard(card)) {
@@ -81,6 +94,13 @@ public class ConquestAEtherScreen extends FScreen {
updateAvailableShards();
}
private void resetFilters() {
btnColorFilter.setSelectedOption(ConquestUtil.getColorFilter(commander.getCard().getRules().getColorIdentity()));
btnTypeFilter.setSelectedOption(AEtherFilter.CREATURE);
btnRarityFilter.setSelectedOption(AEtherFilter.COMMON);
btnCMCFilter.setSelectedOption(AEtherFilter.CMC_LOW_MID);
}
private void updateFilteredPool() {
Predicate<PaperCard> predicate = btnColorFilter.buildFilterPredicate(null);
predicate = btnTypeFilter.buildFilterPredicate(predicate);
@@ -102,8 +122,13 @@ public class ConquestAEtherScreen extends FScreen {
}
private void updateShardCost() {
shardCost = FModel.getConquest().calculateShardCost(filteredPool, pool.size(),
btnColorFilter.selectedOption, btnTypeFilter.selectedOption, btnCMCFilter.selectedOption);
ConquestAwardPool pool = FModel.getConquest().getModel().getCurrentPlane().getAwardPool();
if (filteredPool.isEmpty()) {
shardCost = 0;
}
else {
shardCost = pool.getShardValue(btnRarityFilter.selectedOption.getRarity(), FModel.getConquestPreferences().getPrefInt(CQPref.AETHER_BASE_PULL_COST));
}
display.updateMessage();
}
@@ -306,25 +331,28 @@ public class ConquestAEtherScreen extends FScreen {
if (selectedOption == selectedOption0) { return; }
selectedOption = selectedOption0;
if (selectedOption == AEtherFilter.NONE) {
setIcon(null);
setText("Filter\n" + caption);
FSkinProp skinProp = selectedOption.skinProp;
if (skinProp != null) {
setIcon(FSkin.getImages().get(skinProp));
}
else {
setIcon(FSkin.getImages().get(selectedOption.skinProp));
setText("");
ColorSet color = selectedOption.getColor();
if (color != null) {
setIcon(new ColorSetImage(color));
}
else {
System.out.println("No icon for filter " + selectedOption.name());
setIcon(null);
}
}
}
private Predicate<PaperCard> buildFilterPredicate(Predicate<PaperCard> predicate) {
if (selectedOption != AEtherFilter.NONE) {
if (predicate == null) {
return selectedOption.predicate;
}
return Predicates.and(predicate, selectedOption.predicate);
}
return predicate;
}
@Override
protected void drawContent(Graphics g, float w, float h, final boolean pressed) {

View File

@@ -52,11 +52,10 @@ public class ConquestPrefsScreen extends FScreen {
super("Conquest Preferences", ConquestMenu.getMenu());
scroller.add(new PrefsHeader("AEther Shards", FSkinImage.AETHER_SHARD, PrefsGroup.BOOSTER));
scroller.add(new PrefsOption("Base Card Value", CQPref.AETHER_BASE_VALUE, PrefsGroup.AETHER));
scroller.add(new PrefsOption("Markup Percentage", CQPref.AETHER_MARKUP, PrefsGroup.AETHER));
scroller.add(new PrefsOption("Color Filter Markup", CQPref.AETHER_COLOR_FILTER_MARKUP, PrefsGroup.AETHER));
scroller.add(new PrefsOption("Type Filter Markup", CQPref.AETHER_TYPE_FILTER_MARKUP, PrefsGroup.AETHER));
scroller.add(new PrefsOption("CMC Filter Markup", CQPref.AETHER_CMC_FILTER_MARKUP, PrefsGroup.AETHER));
scroller.add(new PrefsOption("Base Duplicate Value", CQPref.AETHER_BASE_DUPLICATE_VALUE, PrefsGroup.AETHER));
scroller.add(new PrefsOption("Base Exile Value", CQPref.AETHER_BASE_EXILE_VALUE, PrefsGroup.AETHER));
scroller.add(new PrefsOption("Base Retrieve Cost", CQPref.AETHER_BASE_RETRIEVE_COST, PrefsGroup.AETHER));
scroller.add(new PrefsOption("Base Pull Cost", CQPref.AETHER_BASE_PULL_COST, PrefsGroup.AETHER));
scroller.add(new PrefsOption("Starting Shards", CQPref.AETHER_START_SHARDS, PrefsGroup.AETHER));
scroller.add(new PrefsOption("Chaos Wheel Shard Value", CQPref.AETHER_WHEEL_SHARDS, PrefsGroup.AETHER));

View File

@@ -518,6 +518,8 @@ public class FChoiceList<T> extends FList<T> implements ActivateHandler {
}
}
protected class IHasSkinPropRenderer extends DefaultItemRenderer {
private final TextRenderer textRenderer = new TextRenderer(true);
@Override
public void drawValue(Graphics g, T value, FSkinFont font, FSkinColor foreColor, boolean pressed, float x, float y, float w, float h) {
FSkinProp skinProp = ((IHasSkinProp)value).getSkinProp();
@@ -531,7 +533,7 @@ public class FChoiceList<T> extends FList<T> implements ActivateHandler {
x += dx;
w -= dx;
}
super.drawValue(g, value, font, foreColor, pressed, x, y, w, h);
textRenderer.drawText(g, value.toString(), font, foreColor, x, y, w, h, y, h, true, HAlignment.LEFT, true);
}
}

View File

@@ -333,6 +333,10 @@ public class FLabel extends FDisplayObject implements IButton {
else if (iconInBackground || iconScaleAuto) {
iconHeight = h * iconScaleFactor;
iconWidth = iconHeight * aspectRatio;
if (iconWidth > w && iconInBackground) { //ensure background icon stays with label bounds
iconWidth = w;
iconHeight = iconWidth / aspectRatio;
}
}
float iconOffset = iconWidth + insets.x + getExtraGapBetweenIconAndText();

View File

@@ -2,7 +2,7 @@ package forge.planarconquest;
import java.util.ArrayList;
import java.util.List;
import forge.card.CardRarity;
import forge.item.PaperCard;
import forge.model.FModel;
import forge.planarconquest.ConquestPreferences.CQPref;
@@ -10,7 +10,6 @@ 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();
@@ -47,24 +46,24 @@ public class ConquestAwardPool {
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));
//determine multipliers for each rarity based on ratio of odds
commons.multiplier = 1;
uncommons.multiplier = commonOdds / uncommonOdds;
rares.multiplier = commonOdds / rareOdds;
mythics.multiplier = mythics.isEmpty() ? 0 : commonOdds / mythicOdds;
}
public int getShardValue(PaperCard card) {
switch (card.getRarity()) {
public int getShardValue(CardRarity rarity, int baseValue) {
switch (rarity) {
case Common:
return commonValue;
return baseValue;
case Uncommon:
return uncommonValue;
return Math.round(baseValue * uncommons.multiplier);
case Rare:
case Special:
return rareValue;
return Math.round(baseValue * rares.multiplier);
case MythicRare:
return mythicValue;
return Math.round(baseValue * mythics.multiplier);
default:
return 0;
}
@@ -85,6 +84,7 @@ public class ConquestAwardPool {
public class BoosterPool {
private final List<PaperCard> cards = new ArrayList<PaperCard>();
private float multiplier;
private BoosterPool() {
}

View File

@@ -41,7 +41,6 @@ import forge.item.PaperCard;
import forge.match.HostedMatch;
import forge.model.FModel;
import forge.planarconquest.ConquestPreferences.CQPref;
import forge.planarconquest.ConquestUtil.AEtherFilter;
import forge.player.GamePlayerUtil;
import forge.player.LobbyPlayerHuman;
import forge.properties.ForgeConstants;
@@ -221,13 +220,14 @@ public class ConquestController {
//also build list of all rewards including replacement shards for each duplicate card
//build this list in reverse order so commons appear first
int shards = 0;
int baseDuplicateValue = prefs.getPrefInt(CQPref.AETHER_BASE_DUPLICATE_VALUE);
final List<ConquestReward> allRewards = new ArrayList<ConquestReward>();
for (int i = rewards.size() - 1; i >= 0; i--) {
int replacementShards = 0;
PaperCard card = rewards.get(i);
if (model.hasUnlockedCard(card)) {
rewards.remove(i);
replacementShards = pool.getShardValue(card);
replacementShards = pool.getShardValue(card.getRarity(), baseDuplicateValue);
shards += replacementShards;
}
allRewards.add(new ConquestReward(card, replacementShards));
@@ -237,33 +237,4 @@ public class ConquestController {
model.rewardAEtherShards(shards);
return allRewards;
}
public int calculateShardCost(Set<PaperCard> filteredCards, int unfilteredCount, AEtherFilter colorFilter, AEtherFilter typeFilter, AEtherFilter cmcFilter) {
if (filteredCards.isEmpty()) { return 0; }
ConquestAwardPool pool = FModel.getConquest().getModel().getCurrentPlane().getAwardPool();
//determine average value of filtered cards
int totalValue = 0;
for (PaperCard card : filteredCards) {
totalValue += pool.getShardValue(card);
}
ConquestPreferences prefs = FModel.getConquestPreferences();
float averageValue = totalValue / filteredCards.size();
float multiplier = 1f + (float)prefs.getPrefInt(CQPref.AETHER_MARKUP) / 100f;
//increase multipliers based on applied filters
if (colorFilter != AEtherFilter.NONE) {
multiplier += (float)prefs.getPrefInt(CQPref.AETHER_COLOR_FILTER_MARKUP) / 100f;
}
if (typeFilter != AEtherFilter.NONE) {
multiplier += (float)prefs.getPrefInt(CQPref.AETHER_TYPE_FILTER_MARKUP) / 100f;
}
if (cmcFilter != AEtherFilter.NONE) {
multiplier += (float)prefs.getPrefInt(CQPref.AETHER_CMC_FILTER_MARKUP) / 100f;
}
return Math.round(averageValue * multiplier);
}
}

View File

@@ -29,11 +29,10 @@ public class ConquestPreferences extends PreferencesStore<ConquestPreferences.CQ
public static enum CQPref {
CURRENT_CONQUEST("DEFAULT"),
AETHER_BASE_VALUE("100"),
AETHER_MARKUP("40"),
AETHER_COLOR_FILTER_MARKUP("20"),
AETHER_TYPE_FILTER_MARKUP("20"),
AETHER_CMC_FILTER_MARKUP("20"),
AETHER_BASE_DUPLICATE_VALUE("100"),
AETHER_BASE_EXILE_VALUE("75"),
AETHER_BASE_RETRIEVE_COST("150"),
AETHER_BASE_PULL_COST("200"),
AETHER_START_SHARDS("3000"),
AETHER_WHEEL_SHARDS("1000"),

View File

@@ -15,6 +15,7 @@ import forge.card.CardRarity;
import forge.card.CardRules;
import forge.card.CardType;
import forge.card.CardType.CoreType;
import forge.card.mana.ManaCostShard;
import forge.card.ColorSet;
import forge.card.MagicColor;
import forge.deck.CardPool;
@@ -147,19 +148,39 @@ public class ConquestUtil {
}
public static enum AEtherFilter implements IHasSkinProp {
NONE (null, null, "(None)"),
W (null, new ColorFilter(MagicColor.WHITE), "Playable in {W}"),
U (null, new ColorFilter(MagicColor.BLUE), "Playable in {U}"),
B (null, new ColorFilter(MagicColor.BLACK), "Playable in {B}"),
R (null, new ColorFilter(MagicColor.RED), "Playable in {R}"),
G (null, new ColorFilter(MagicColor.GREEN), "Playable in {G}"),
WHITE (FSkinProp.IMG_MANA_W, new ColorFilter(MagicColor.WHITE), "White"),
BLUE (FSkinProp.IMG_MANA_U, new ColorFilter(MagicColor.BLUE), "Blue"),
BLACK (FSkinProp.IMG_MANA_B, new ColorFilter(MagicColor.BLACK), "Black"),
RED (FSkinProp.IMG_MANA_R, new ColorFilter(MagicColor.RED), "Red"),
GREEN (FSkinProp.IMG_MANA_G, new ColorFilter(MagicColor.GREEN), "Green"),
COLORLESS (FSkinProp.IMG_MANA_COLORLESS, new ColorFilter(MagicColor.COLORLESS), "Colorless"),
WU (null, new ColorFilter(MagicColor.WHITE | MagicColor.BLUE), "Playable in {W}{U}"),
WB (null, new ColorFilter(MagicColor.WHITE | MagicColor.BLACK), "Playable in {W}{B}"),
UB (null, new ColorFilter(MagicColor.BLUE | MagicColor.BLACK), "Playable in {U}{B}"),
UR (null, new ColorFilter(MagicColor.BLUE | MagicColor.RED), "Playable in {U}{R}"),
BR (null, new ColorFilter(MagicColor.BLACK | MagicColor.RED), "Playable in {B}{R}"),
BG (null, new ColorFilter(MagicColor.BLACK | MagicColor.GREEN), "Playable in {B}{G}"),
RG (null, new ColorFilter(MagicColor.RED | MagicColor.GREEN), "Playable in {R}{G}"),
RW (null, new ColorFilter(MagicColor.RED | MagicColor.WHITE), "Playable in {R}{W}"),
GW (null, new ColorFilter(MagicColor.GREEN | MagicColor.WHITE), "Playable in {G}{W}"),
GU (null, new ColorFilter(MagicColor.GREEN | MagicColor.BLUE), "Playable in {G}{U}"),
WUB (null, new ColorFilter(MagicColor.WHITE | MagicColor.BLUE | MagicColor.BLACK), "Playable in {W}{U}{B}"),
WBG (null, new ColorFilter(MagicColor.WHITE | MagicColor.BLACK | MagicColor.GREEN), "Playable in {W}{B}{G}"),
UBR (null, new ColorFilter(MagicColor.BLUE | MagicColor.BLACK | MagicColor.RED), "Playable in {U}{B}{R}"),
URW (null, new ColorFilter(MagicColor.BLUE | MagicColor.RED | MagicColor.WHITE), "Playable in {U}{R}{W}"),
BRG (null, new ColorFilter(MagicColor.BLACK | MagicColor.RED | MagicColor.GREEN), "Playable in {B}{R}{G}"),
BGU (null, new ColorFilter(MagicColor.BLACK | MagicColor.GREEN | MagicColor.BLUE), "Playable in {B}{G}{U}"),
RGW (null, new ColorFilter(MagicColor.RED | MagicColor.GREEN | MagicColor.WHITE), "Playable in {R}{G}{W}"),
RWB (null, new ColorFilter(MagicColor.RED | MagicColor.WHITE | MagicColor.BLACK), "Playable in {R}{W}{B}"),
GWU (null, new ColorFilter(MagicColor.GREEN | MagicColor.WHITE | MagicColor.BLUE), "Playable in {G}{W}{U}"),
GUR (null, new ColorFilter(MagicColor.GREEN | MagicColor.BLUE | MagicColor.RED), "Playable in {G}{U}{R}"),
WUBRG (null, new ColorFilter(MagicColor.ALL_COLORS), "Playable in {W}{U}{B}{R}{G}"),
CREATURE (FSkinProp.IMG_CREATURE, new TypeFilter(EnumSet.of(CoreType.Creature)), "Creature"),
ARTIFACT_ENCHANTMENT (FSkinProp.IMG_ENCHANTMENT, new TypeFilter(EnumSet.of(CoreType.Artifact, CoreType.Enchantment, CoreType.Planeswalker)), "Artifact, Enchantment, or Planeswalker"),
NONCREATURE_PERMANENT (FSkinProp.IMG_ENCHANTMENT, new TypeFilter(EnumSet.of(CoreType.Artifact, CoreType.Enchantment, CoreType.Planeswalker, CoreType.Land)), "Noncreature Permanent"),
INSTANT_SORCERY (FSkinProp.IMG_SORCERY, new TypeFilter(EnumSet.of(CoreType.Instant, CoreType.Sorcery)), "Instant or Sorcery"),
LAND (FSkinProp.IMG_LAND, new TypeFilter(EnumSet.of(CoreType.Land)), "Land"),
COMMON (FSkinProp.IMG_PW_BADGE_COMMON, new RarityFilter(CardRarity.Common), "Common"),
UNCOMMON (FSkinProp.IMG_PW_BADGE_UNCOMMON, new RarityFilter(CardRarity.Uncommon), "Uncommon"),
@@ -186,59 +207,103 @@ public class ConquestUtil {
return skinProp;
}
public ColorSet getColor() {
if (predicate instanceof ColorFilter) {
return ((ColorFilter)predicate).color;
}
return null;
}
public EnumSet<CoreType> getTypes() {
if (predicate instanceof ColorFilter) {
return ((TypeFilter)predicate).types;
}
return null;
}
public CardRarity getRarity() {
if (predicate instanceof RarityFilter) {
return ((RarityFilter)predicate).rarity;
}
return null;
}
@Override
public String toString() {
return caption;
}
}
public static AEtherFilter getColorFilter(ColorSet color) {
String name = "";
for (ManaCostShard s : color.getOrderedShards()) {
name += s.toString();
}
name = name.replaceAll("[{}]", ""); //remove all brackets
try {
return AEtherFilter.valueOf(name);
}
catch (Exception e) {
System.err.println("No color filter with name " + name);
return AEtherFilter.WUBRG; //return 5-color filter as fallback
}
}
public static final AEtherFilter[] COLOR_FILTERS = new AEtherFilter[] {
AEtherFilter.NONE,
AEtherFilter.WHITE,
AEtherFilter.BLUE,
AEtherFilter.BLACK,
AEtherFilter.RED,
AEtherFilter.GREEN,
AEtherFilter.COLORLESS };
AEtherFilter.W,
AEtherFilter.U,
AEtherFilter.B,
AEtherFilter.R,
AEtherFilter.G,
AEtherFilter.WU,
AEtherFilter.WB,
AEtherFilter.UB,
AEtherFilter.UR,
AEtherFilter.BR,
AEtherFilter.BG,
AEtherFilter.RG,
AEtherFilter.RW,
AEtherFilter.GW,
AEtherFilter.GU,
AEtherFilter.WUB,
AEtherFilter.WBG,
AEtherFilter.UBR,
AEtherFilter.URW,
AEtherFilter.BRG,
AEtherFilter.BGU,
AEtherFilter.RGW,
AEtherFilter.RWB,
AEtherFilter.GWU,
AEtherFilter.GUR,
AEtherFilter.WUBRG };
public static final AEtherFilter[] TYPE_FILTERS = new AEtherFilter[] {
AEtherFilter.NONE,
AEtherFilter.CREATURE,
AEtherFilter.ARTIFACT_ENCHANTMENT,
AEtherFilter.INSTANT_SORCERY,
AEtherFilter.LAND };
AEtherFilter.NONCREATURE_PERMANENT,
AEtherFilter.INSTANT_SORCERY };
public static final AEtherFilter[] RARITY_FILTERS = new AEtherFilter[] {
AEtherFilter.NONE,
AEtherFilter.COMMON,
AEtherFilter.UNCOMMON,
AEtherFilter.RARE,
AEtherFilter.MYTHIC };
public static final AEtherFilter[] CMC_FILTERS = new AEtherFilter[] {
AEtherFilter.NONE,
AEtherFilter.CMC_LOW,
AEtherFilter.CMC_LOW_MID,
AEtherFilter.CMC_MID_HIGH,
AEtherFilter.CMC_HIGH };
private static class ColorFilter implements Predicate<PaperCard> {
private final byte color;
private final ColorSet color;
private ColorFilter(byte color0) {
color = color0;
private ColorFilter(int colorMask0) {
color = ColorSet.fromMask(colorMask0);
}
@Override
public boolean apply(PaperCard card) {
//use color identity for lands and color for other cards
CardRules cardRules = card.getRules();
ColorSet cardColor = cardRules.getType().isLand() ? cardRules.getColorIdentity() : cardRules.getColor();
if (color == MagicColor.COLORLESS) {
return cardColor.isColorless();
}
return cardColor.hasAllColors(color);
return card.getRules().getColorIdentity().hasNoColorsExcept(color);
}
}