From 5af9e90a2e8fe2d901f1f477a34d9c9b4b552638 Mon Sep 17 00:00:00 2001 From: drdev Date: Sun, 20 Mar 2016 16:29:49 +0000 Subject: [PATCH] Tweak cost and value multipliers for non-commons --- .gitattributes | 1 + .../src/main/java/forge/card/CardRarity.java | 4 + .../src/forge/card/ColorSetImage.java | 37 +++++++ .../planarconquest/ConquestAEtherScreen.java | 55 +++++++++- .../planarconquest/ConquestPrefsScreen.java | 3 + .../src/main/java/forge/model/FModel.java | 2 + .../planarconquest/ConquestAwardPool.java | 29 +---- .../planarconquest/ConquestPreferences.java | 10 ++ .../forge/planarconquest/ConquestUtil.java | 103 ++++++++++++++---- .../forge/properties/PreferencesStore.java | 2 +- 10 files changed, 192 insertions(+), 54 deletions(-) create mode 100644 forge-gui-mobile/src/forge/card/ColorSetImage.java diff --git a/.gitattributes b/.gitattributes index 953d08c7231..22fc3ba1b32 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1243,6 +1243,7 @@ forge-gui-mobile/src/forge/card/CardImageRenderer.java -text forge-gui-mobile/src/forge/card/CardListPreview.java -text forge-gui-mobile/src/forge/card/CardRenderer.java -text forge-gui-mobile/src/forge/card/CardZoom.java -text +forge-gui-mobile/src/forge/card/ColorSetImage.java -text forge-gui-mobile/src/forge/card/GameEntityPicker.java -text forge-gui-mobile/src/forge/deck/AddBasicLandsDialog.java -text forge-gui-mobile/src/forge/deck/FDeckChooser.java -text diff --git a/forge-core/src/main/java/forge/card/CardRarity.java b/forge-core/src/main/java/forge/card/CardRarity.java index 8bd45eecd7e..f507eeaa349 100644 --- a/forge-core/src/main/java/forge/card/CardRarity.java +++ b/forge-core/src/main/java/forge/card/CardRarity.java @@ -44,6 +44,10 @@ public enum CardRarity { return shortName; } + public String getLongName() { + return longName; + } + public static CardRarity smartValueOf(String input) { for (CardRarity r : CardRarity.values()) { if (r.name().equalsIgnoreCase(input) || r.shortName.equalsIgnoreCase(input) || r.longName.equalsIgnoreCase(input)) { diff --git a/forge-gui-mobile/src/forge/card/ColorSetImage.java b/forge-gui-mobile/src/forge/card/ColorSetImage.java new file mode 100644 index 00000000000..13598b2dece --- /dev/null +++ b/forge-gui-mobile/src/forge/card/ColorSetImage.java @@ -0,0 +1,37 @@ +package forge.card; + +import forge.Graphics; +import forge.assets.FImage; +import forge.assets.FSkinImage; + +public class ColorSetImage implements FImage { + private final ColorSet colorSet; + private final int shardCount; + + public ColorSetImage(ColorSet colorSet0) { + colorSet = colorSet0; + shardCount = colorSet.getOrderedShards().length; + } + + @Override + public float getWidth() { + return FSkinImage.MANA_W.getWidth() * shardCount; + } + + @Override + public float getHeight() { + return FSkinImage.MANA_W.getHeight(); + } + + @Override + public void draw(Graphics g, float x, float y, float w, float h) { + float imageSize = w / shardCount; + if (imageSize > h) { + imageSize = h; + float w0 = imageSize * shardCount; + x += (w - w0) / 2; + w = w0; + } + CardFaceSymbols.drawColorSet(g, colorSet, x, y, imageSize); + } +} diff --git a/forge-gui-mobile/src/forge/screens/planarconquest/ConquestAEtherScreen.java b/forge-gui-mobile/src/forge/screens/planarconquest/ConquestAEtherScreen.java index 55427967b6e..e7426852dd9 100644 --- a/forge-gui-mobile/src/forge/screens/planarconquest/ConquestAEtherScreen.java +++ b/forge-gui-mobile/src/forge/screens/planarconquest/ConquestAEtherScreen.java @@ -10,6 +10,7 @@ import com.badlogic.gdx.math.Rectangle; import com.google.common.base.Predicate; import com.google.common.base.Predicates; import com.google.common.collect.ImmutableList; +import com.google.common.collect.Iterables; import forge.Graphics; import forge.animation.ForgeAnimation; @@ -19,6 +20,7 @@ import forge.assets.FSkinFont; import forge.assets.FSkinProp; import forge.assets.FSkinTexture; import forge.assets.TextRenderer; +import forge.card.CardRarity; import forge.card.CardRenderer; import forge.card.CardZoom; import forge.card.ColorSet; @@ -127,7 +129,7 @@ public class ConquestAEtherScreen extends FScreen { shardCost = 0; } else { - shardCost = pool.getShardValue(btnRarityFilter.selectedOption.getRarity(), FModel.getConquestPreferences().getPrefInt(CQPref.AETHER_BASE_PULL_COST)); + shardCost = pool.getShardValue(btnRarityFilter.selectedOption.getRarity(0), FModel.getConquestPreferences().getPrefInt(CQPref.AETHER_BASE_PULL_COST)); } display.updateMessage(); } @@ -138,7 +140,50 @@ public class ConquestAEtherScreen extends FScreen { ConquestData model = FModel.getConquest().getModel(); if (model.getAEtherShards() < shardCost) { return; } - PaperCard card = Aggregates.random(filteredPool); + //determine final pool to pull from based on rarity odds + Iterable rewardPool; + boolean lowerRarity = true; + CardRarity minRarity = btnRarityFilter.selectedOption.getRarity(0); + CardRarity rarity = btnRarityFilter.selectedOption.getRarity(Math.random()); + while (true) { + final CardRarity allowedRarity = rarity; + rewardPool = Iterables.filter(filteredPool, new Predicate() { + @Override + public boolean apply(PaperCard card) { + if (allowedRarity == card.getRarity()) { return true; } + if (allowedRarity == CardRarity.Rare && card.getRarity() == CardRarity.Special) { return true; } + return false; + } + }); + if (Iterables.isEmpty(rewardPool)) { //if pool is empty, must reduce rarity and try again + if (rarity == minRarity) { + if (lowerRarity) { lowerRarity = false; } //switch to increasing rarity if min rarity empty + else { break; } //shouldn't happen, but prevent infinite loop + } + switch (rarity) { + case MythicRare: + rarity = lowerRarity ? CardRarity.Rare : CardRarity.Common; + continue; + case Rare: + rarity = lowerRarity ? CardRarity.Uncommon : CardRarity.MythicRare; + continue; + case Uncommon: + rarity = lowerRarity ? CardRarity.Common : CardRarity.Rare; + continue; + case Common: + if (lowerRarity) { break; } //shouldn't happen + rarity = CardRarity.Uncommon; + continue; + default: + break; + } + } + break; + } + + PaperCard card = Aggregates.random(rewardPool); + if (card == null) { return; } //shouldn't happen, but prevent crash if it does + pool.remove(card); filteredPool.remove(card); @@ -331,7 +376,7 @@ public class ConquestAEtherScreen extends FScreen { if (selectedOption == selectedOption0) { return; } selectedOption = selectedOption0; - FSkinProp skinProp = selectedOption.skinProp; + FSkinProp skinProp = selectedOption.getSkinProp(); if (skinProp != null) { setIcon(FSkin.getImages().get(skinProp)); } @@ -349,9 +394,9 @@ public class ConquestAEtherScreen extends FScreen { private Predicate buildFilterPredicate(Predicate predicate) { if (predicate == null) { - return selectedOption.predicate; + return selectedOption.getPredicate(); } - return Predicates.and(predicate, selectedOption.predicate); + return Predicates.and(predicate, selectedOption.getPredicate()); } @Override diff --git a/forge-gui-mobile/src/forge/screens/planarconquest/ConquestPrefsScreen.java b/forge-gui-mobile/src/forge/screens/planarconquest/ConquestPrefsScreen.java index 1bd9fc54392..49712cfbc20 100644 --- a/forge-gui-mobile/src/forge/screens/planarconquest/ConquestPrefsScreen.java +++ b/forge-gui-mobile/src/forge/screens/planarconquest/ConquestPrefsScreen.java @@ -56,6 +56,9 @@ public class ConquestPrefsScreen extends FScreen { 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("Uncommon Multiplier", CQPref.AETHER_UNCOMMON_MULTIPLIER, PrefsGroup.AETHER)); + scroller.add(new PrefsOption("Rare Multiplier", CQPref.AETHER_RARE_MULTIPLIER, PrefsGroup.AETHER)); + scroller.add(new PrefsOption("Mythic Multiplier", CQPref.AETHER_MYTHIC_MULTIPLIER, 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)); diff --git a/forge-gui/src/main/java/forge/model/FModel.java b/forge-gui/src/main/java/forge/model/FModel.java index dcc046abe89..4d76d53c1a0 100644 --- a/forge-gui/src/main/java/forge/model/FModel.java +++ b/forge-gui/src/main/java/forge/model/FModel.java @@ -37,6 +37,7 @@ import forge.limited.GauntletMini; import forge.planarconquest.ConquestController; import forge.planarconquest.ConquestPlane; import forge.planarconquest.ConquestPreferences; +import forge.planarconquest.ConquestUtil; import forge.player.GamePlayerUtil; import forge.properties.ForgeConstants; import forge.properties.ForgePreferences; @@ -178,6 +179,7 @@ public final class FModel { CardPreferences.load(); DeckPreferences.load(); ItemManagerConfig.load(); + ConquestUtil.updateRarityFilterOdds(); achievements = new HashMap<>(); achievements.put(GameType.Constructed, new ConstructedAchievements()); diff --git a/forge-gui/src/main/java/forge/planarconquest/ConquestAwardPool.java b/forge-gui/src/main/java/forge/planarconquest/ConquestAwardPool.java index ec29b0db22e..1e4dedd59ca 100644 --- a/forge-gui/src/main/java/forge/planarconquest/ConquestAwardPool.java +++ b/forge-gui/src/main/java/forge/planarconquest/ConquestAwardPool.java @@ -12,8 +12,6 @@ public class ConquestAwardPool { private final BoosterPool commons, uncommons, rares, mythics; public ConquestAwardPool(Iterable cards) { - ConquestPreferences prefs = FModel.getConquestPreferences(); - commons = new BoosterPool(); uncommons = new BoosterPool(); rares = new BoosterPool(); @@ -38,32 +36,20 @@ public class ConquestAwardPool { 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 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(CardRarity rarity, int baseValue) { + ConquestPreferences prefs = FModel.getConquestPreferences(); switch (rarity) { case Common: return baseValue; case Uncommon: - return Math.round(baseValue * uncommons.multiplier); + return Math.round((float)baseValue * (float)prefs.getPrefInt(CQPref.AETHER_UNCOMMON_MULTIPLIER)); case Rare: case Special: - return Math.round(baseValue * rares.multiplier); + return Math.round((float)baseValue * (float)prefs.getPrefInt(CQPref.AETHER_RARE_MULTIPLIER)); case MythicRare: - return Math.round(baseValue * mythics.multiplier); + return Math.round((float)baseValue * (float)prefs.getPrefInt(CQPref.AETHER_MYTHIC_MULTIPLIER)); default: return 0; } @@ -84,7 +70,6 @@ public class ConquestAwardPool { public class BoosterPool { private final List cards = new ArrayList(); - private float multiplier; private BoosterPool() { } @@ -93,12 +78,6 @@ public class ConquestAwardPool { 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); } diff --git a/forge-gui/src/main/java/forge/planarconquest/ConquestPreferences.java b/forge-gui/src/main/java/forge/planarconquest/ConquestPreferences.java index 502a4749cb6..6ca5baabe8e 100644 --- a/forge-gui/src/main/java/forge/planarconquest/ConquestPreferences.java +++ b/forge-gui/src/main/java/forge/planarconquest/ConquestPreferences.java @@ -19,6 +19,7 @@ package forge.planarconquest; import forge.properties.ForgeConstants; import forge.properties.PreferencesStore; + import java.io.Serializable; @SuppressWarnings("serial") @@ -33,6 +34,9 @@ public class ConquestPreferences extends PreferencesStore predicate; - public final String caption; + private final FSkinProp skinProp; + private final Predicate predicate; + private String caption; private AEtherFilter(final FSkinProp skinProp0, final Predicate predicate0, final String caption0) { skinProp = skinProp0; @@ -207,6 +209,10 @@ public class ConquestUtil { return skinProp; } + public Predicate getPredicate() { + return predicate; + } + public ColorSet getColor() { if (predicate instanceof ColorFilter) { return ((ColorFilter)predicate).color; @@ -214,16 +220,19 @@ public class ConquestUtil { return null; } - public EnumSet getTypes() { - if (predicate instanceof ColorFilter) { - return ((TypeFilter)predicate).types; - } - return null; - } - - public CardRarity getRarity() { + public CardRarity getRarity(double randomSeed) { if (predicate instanceof RarityFilter) { - return ((RarityFilter)predicate).rarity; + float total = 0; + CardRarity rarity = null; + EnumMap rarityOdds = ((RarityFilter)predicate).rarityOdds; + for (Entry entry : rarityOdds.entrySet()) { + rarity = entry.getKey(); + total += entry.getValue(); + if (randomSeed < total) { + return rarity; + } + } + return rarity; } return null; } @@ -249,6 +258,25 @@ public class ConquestUtil { } } + public static void updateRarityFilterOdds() { + ConquestPreferences prefs = FModel.getConquestPreferences(); + + EnumMap odds = new EnumMap(CardRarity.class); + double commonsPerBooster = prefs.getPrefInt(CQPref.BOOSTER_COMMONS); + double uncommonPerBooster = prefs.getPrefInt(CQPref.BOOSTER_UNCOMMONS); + double raresPerBooster = prefs.getPrefInt(CQPref.BOOSTER_RARES); + double mythicsPerBooster = raresPerBooster / (double)prefs.getPrefInt(CQPref.BOOSTERS_PER_MYTHIC); + + odds.put(CardRarity.Common, 1d); + odds.put(CardRarity.Uncommon, uncommonPerBooster / commonsPerBooster); + odds.put(CardRarity.Rare, raresPerBooster / commonsPerBooster); + odds.put(CardRarity.MythicRare, mythicsPerBooster / commonsPerBooster); + + for (AEtherFilter filter : RARITY_FILTERS) { + filter.caption = ((RarityFilter)filter.predicate).updateOdds(odds); + } + } + public static final AEtherFilter[] COLOR_FILTERS = new AEtherFilter[] { AEtherFilter.W, AEtherFilter.U, @@ -327,18 +355,47 @@ public class ConquestUtil { } private static class RarityFilter implements Predicate { - private final CardRarity rarity; + private final EnumMap rarityOdds; - private RarityFilter(CardRarity rarity0) { - rarity = rarity0; + private RarityFilter(EnumSet rarities0) { + rarityOdds = new EnumMap(CardRarity.class); + for (CardRarity rarity : rarities0) { + rarityOdds.put(rarity, 0d); //values will be set later + } + } + + private String updateOdds(EnumMap oddsLookup) { + double baseOdds = 0; + double remainingOdds = 1; + CardRarity baseRarity = null; + String caption = ""; + + for (CardRarity rarity : rarityOdds.keySet()) { + Double odds = oddsLookup.get(rarity); + if (odds == null) { continue; } //skip Special rarity + + if (baseRarity == null) { + baseRarity = rarity; + baseOdds = odds; + } + else { + odds /= baseOdds; + remainingOdds -= odds; + caption += ", " + rarity.getLongName() + " (" + (Math.round(1000 * odds) / 10) + "%)"; //round to nearest single decimal point + rarityOdds.put(rarity, odds); + } + } + + //prepend base rarity and odds + caption = baseRarity.getLongName() + " (" + (Math.round(1000 * remainingOdds) / 10) + "%)" + caption; + rarityOdds.put(baseRarity, remainingOdds); + + return caption; } @Override public boolean apply(PaperCard card) { - CardRarity cardRarity = card.getRarity(); - if (cardRarity == rarity) { return true; } - if (cardRarity == CardRarity.Special && rarity == CardRarity.Rare) { return true; } //treat specials as rares - return false; + return rarityOdds.containsKey(card.getRarity()); } } diff --git a/forge-gui/src/main/java/forge/properties/PreferencesStore.java b/forge-gui/src/main/java/forge/properties/PreferencesStore.java index 3423bd7534e..c18cb3a97d5 100644 --- a/forge-gui/src/main/java/forge/properties/PreferencesStore.java +++ b/forge-gui/src/main/java/forge/properties/PreferencesStore.java @@ -66,7 +66,7 @@ public abstract class PreferencesStore> { protected abstract T valueOf(String name); protected abstract String getPrefDefault(T key); - public final void save() { + public void save() { BufferedWriter writer = null; try { writer = new BufferedWriter(new FileWriter(filename));