diff --git a/forge-game/src/main/java/forge/game/GameFormat.java b/forge-game/src/main/java/forge/game/GameFormat.java index 29b1474c8c2..e546f721cda 100644 --- a/forge-game/src/main/java/forge/game/GameFormat.java +++ b/forge-game/src/main/java/forge/game/GameFormat.java @@ -137,22 +137,22 @@ public class GameFormat implements Comparable { this.filterRules = this.buildFilterRules(); this.filterPrinted = this.buildFilterPrinted(); } - private Predicate buildFilter(boolean printed) { - Predicate p = Predicates.not(IPaperCard.Predicates.names(this.bannedCardNames_ro)); - if (!this.allowedSetCodes_ro.isEmpty()) { + protected Predicate buildFilter(boolean printed) { + Predicate p = Predicates.not(IPaperCard.Predicates.names(this.getBannedCardNames())); + if (!this.getAllowedSetCodes().isEmpty()) { p = Predicates.and(p, printed ? - IPaperCard.Predicates.printedInSets(this.allowedSetCodes_ro, printed) : - StaticData.instance().getCommonCards().wasPrintedInSets(this.allowedSetCodes_ro)); + IPaperCard.Predicates.printedInSets(this.getAllowedSetCodes(), printed) : + StaticData.instance().getCommonCards().wasPrintedInSets(this.getAllowedSetCodes())); } - if (!this.allowedRarities.isEmpty()) { + if (!this.getAllowedRarities().isEmpty()) { List> crp = Lists.newArrayList(); - for (CardRarity cr: this.allowedRarities) { + for (CardRarity cr: this.getAllowedRarities()) { crp.add(StaticData.instance().getCommonCards().wasPrintedAtRarity(cr)); } p = Predicates.and(p, Predicates.or(crp)); } - if (!this.additionalCardNames_ro.isEmpty()) { - p = Predicates.or(p, IPaperCard.Predicates.names(this.additionalCardNames_ro)); + if (!this.getAdditionalCards().isEmpty()) { + p = Predicates.or(p, IPaperCard.Predicates.names(this.getAdditionalCards())); } return p; } @@ -241,7 +241,7 @@ public class GameFormat implements Comparable { } public boolean isSetLegal(final String setCode) { - return this.allowedSetCodes_ro.isEmpty() || this.allowedSetCodes_ro.contains(setCode); + return this.getAllowedSetCodes().isEmpty() || this.getAllowedSetCodes().contains(setCode); } private boolean isPoolLegal(final CardPool allCards) { @@ -257,7 +257,7 @@ public class GameFormat implements Comparable { { final List erroneousCI = new ArrayList<>(); for (Entry poolEntry : allCards) { - if (!filterRules.apply(poolEntry.getKey())) { + if (!getFilterRules().apply(poolEntry.getKey())) { erroneousCI.add(poolEntry.getKey()); } } @@ -270,12 +270,12 @@ public class GameFormat implements Comparable { } } // Check number of restricted and legendary-restricted cards - if(!restrictedCardNames_ro.isEmpty() || restrictedLegendary ) { + if(!getRestrictedCards().isEmpty() || isRestrictedLegendary() ) { final List erroneousRestricted = new ArrayList<>(); for (Entry poolEntry : allCards) { - boolean isRestricted = restrictedCardNames_ro.contains(poolEntry.getKey().getName()); + boolean isRestricted = getRestrictedCards().contains(poolEntry.getKey().getName()); boolean isLegendaryNonPlaneswalker = poolEntry.getKey().getRules().getType().isLegendary() - && !poolEntry.getKey().getRules().getType().isPlaneswalker() && restrictedLegendary; + && !poolEntry.getKey().getRules().getType().isPlaneswalker() && isRestrictedLegendary(); if( poolEntry.getValue() > 1 && (isRestricted || isLegendaryNonPlaneswalker)) { erroneousRestricted.add(poolEntry.getKey()); } @@ -558,6 +558,10 @@ public class GameFormat implements Comparable { return this.map.get("Modern"); } + public GameFormat getVintage() { + return this.map.get("Vintage"); + } + public GameFormat getFormat(String format) { return this.map.get(format); } diff --git a/forge-gui/res/quest/world/worlds.txt b/forge-gui/res/quest/world/worlds.txt index 15f8c8a23d1..dbec86fc79c 100644 --- a/forge-gui/res/quest/world/worlds.txt +++ b/forge-gui/res/quest/world/worlds.txt @@ -3,6 +3,7 @@ Name:Random Standard Name:Random Pioneer Name:Random Modern Name:Random Commander +Name:Evolving Wilds Name:Amonkhet|Dir:Amonkhet|Sets:AKH, HOU, AKR Name:Jamuraa|Dir:jamuraa|Sets:5ED, ARN, MIR, VIS, WTH Name:Kamigawa|Dir:2004 Kamigawa|Sets:CHK, BOK, SOK diff --git a/forge-gui/src/main/java/forge/gamemodes/quest/QuestUtilCards.java b/forge-gui/src/main/java/forge/gamemodes/quest/QuestUtilCards.java index 59de5496f12..3884fee2a26 100644 --- a/forge-gui/src/main/java/forge/gamemodes/quest/QuestUtilCards.java +++ b/forge-gui/src/main/java/forge/gamemodes/quest/QuestUtilCards.java @@ -561,7 +561,7 @@ public final class QuestUtilCards { * @return the predicate */ public static Predicate isLegalInQuestFormat(final GameFormatQuest qFormat) { - return GameFormatQuest.Predicates.isLegalInFormatQuest(qFormat); + return GameFormatQuest.QPredicates.isLegalInFormatQuest(qFormat); } diff --git a/forge-gui/src/main/java/forge/gamemodes/quest/QuestWorld.java b/forge-gui/src/main/java/forge/gamemodes/quest/QuestWorld.java index 18f6e19d93f..10f06900152 100644 --- a/forge-gui/src/main/java/forge/gamemodes/quest/QuestWorld.java +++ b/forge-gui/src/main/java/forge/gamemodes/quest/QuestWorld.java @@ -26,9 +26,12 @@ import java.util.Set; import com.google.common.base.Function; +import forge.card.CardEdition; import forge.deck.Deck; import forge.game.GameFormat; import forge.gamemodes.quest.data.GameFormatQuest; +import forge.gamemodes.quest.setrotation.ISetRotation; +import forge.gamemodes.quest.setrotation.QueueRandomRotation; import forge.item.PaperCard; import forge.model.FModel; import forge.util.storage.StorageReaderFile; @@ -46,6 +49,7 @@ public class QuestWorld implements Comparable{ public static final String MODERNWORLDNAME = "Random Modern"; public static final String RANDOMCOMMANDERWORLDNAME = "Random Commander"; public static final String MAINWORLDNAME = "Main world"; + public static final String EVOLVINGWILDSWORLDNAME = "Evolving Wilds"; private boolean isCustom; @@ -217,6 +221,20 @@ public class QuestWorld implements Comparable{ FModel.getFormats().getFormat("Commander").getBannedCardNames(),false); } + if (useName.equalsIgnoreCase(QuestWorld.EVOLVINGWILDSWORLDNAME)){ + ISetRotation rot = new QueueRandomRotation(6, 5, 1); + List allowedCodes = new ArrayList<>(); + for (CardEdition edition : FModel.getMagicDb().getEditionsTypeMap().get(CardEdition.Type.CORE)) { + allowedCodes.add(edition.getCode()); + } + for (CardEdition edition : FModel.getMagicDb().getEditionsTypeMap().get(CardEdition.Type.EXPANSION)) { + allowedCodes.add(edition.getCode()); + } + useFormat = new GameFormatQuest(QuestWorld.EVOLVINGWILDSWORLDNAME, + allowedCodes, + FModel.getFormats().getVintage().getBannedCardNames(),false, rot); + } + // System.out.println("Creating quest world " + useName + " (index " + useIdx + ", dir: " + useDir); // if (useFormat != null) { System.out.println("SETS: " + sets + "\nBANNED: " + bannedCards); } diff --git a/forge-gui/src/main/java/forge/gamemodes/quest/data/GameFormatQuest.java b/forge-gui/src/main/java/forge/gamemodes/quest/data/GameFormatQuest.java index 6a259c3a370..fc63af93743 100644 --- a/forge-gui/src/main/java/forge/gamemodes/quest/data/GameFormatQuest.java +++ b/forge-gui/src/main/java/forge/gamemodes/quest/data/GameFormatQuest.java @@ -21,9 +21,10 @@ import java.util.ArrayList; import java.util.List; import com.google.common.base.Predicate; - import forge.card.CardEdition; import forge.game.GameFormat; +import forge.gamemodes.quest.setrotation.ISetRotation; +import forge.item.PaperCard; import forge.model.FModel; @@ -38,6 +39,31 @@ public final class GameFormatQuest extends GameFormat { private final boolean allowUnlocks; private int unlocksUsed = 0; + private ISetRotation setRotation; + + @Override + public List getAllowedSetCodes() { + if(setRotation != null) + return setRotation.getCurrentSetCodes(super.getAllowedSetCodes()); + return super.getAllowedSetCodes(); + } + + @Override + public Predicate getFilterRules() { + // Filter must be continuously rebuilt if the format is mutable + if(setRotation != null) + return super.buildFilter(false); + return super.getFilterRules(); + } + + @Override + public Predicate getFilterPrinted() { + // Filter must be continuously rebuilt if the format is mutable + if(setRotation != null) + return super.buildFilter(true); + return super.getFilterRules(); + } + /** * Instantiates a new game format based on two lists. * @@ -48,11 +74,27 @@ public final class GameFormatQuest extends GameFormat { public GameFormatQuest(final String newName, final List setsToAllow, final List cardsToBan) { super(newName, setsToAllow, cardsToBan); allowUnlocks = false; + setRotation = null; } public GameFormatQuest(final String newName, final List setsToAllow, final List cardsToBan, boolean allowSetUnlocks) { super(newName, setsToAllow, cardsToBan); allowUnlocks = allowSetUnlocks; + setRotation = null; + } + + /** + * Instantiates a format that uses an ISetRotation to automatically rotate sets in and out + * @param newName + * @param setsToAllow + * @param cardsToBan + * @param allowSetUnlocks + * @param setRotation an ISetRotation that determines the currently allowed sets + */ + public GameFormatQuest(final String newName, final List setsToAllow, final List cardsToBan, boolean allowSetUnlocks, ISetRotation setRotation) { + super(newName, setsToAllow, cardsToBan); + allowUnlocks = allowSetUnlocks; + this.setRotation = setRotation; } /** @@ -60,12 +102,14 @@ public final class GameFormatQuest extends GameFormat { * * @param toCopy an existing format * @param allowSetUnlocks + * @param setRotation */ - public GameFormatQuest(final GameFormat toCopy, boolean allowSetUnlocks) { + public GameFormatQuest(final GameFormat toCopy, boolean allowSetUnlocks, ISetRotation setRotation) { super(toCopy.getName(), toCopy.getEffectiveDate(), toCopy.getAllowedSetCodes(), toCopy.getBannedCardNames(), toCopy.getRestrictedCards(), toCopy.isRestrictedLegendary(),toCopy.getAdditionalCards(), toCopy.getAllowedRarities(), toCopy.getIndex(), FormatType.CUSTOM, FormatSubType.CUSTOM); allowUnlocks = allowSetUnlocks; + this.setRotation = setRotation; } /** @@ -118,7 +162,7 @@ public final class GameFormatQuest extends GameFormat { return unlocksUsed; } - public abstract static class Predicates { + public abstract static class QPredicates { /** * Checks if is legal in quest format. * diff --git a/forge-gui/src/main/java/forge/gamemodes/quest/data/QuestData.java b/forge-gui/src/main/java/forge/gamemodes/quest/data/QuestData.java index 390ece7a5a7..ebe426698cc 100644 --- a/forge-gui/src/main/java/forge/gamemodes/quest/data/QuestData.java +++ b/forge-gui/src/main/java/forge/gamemodes/quest/data/QuestData.java @@ -100,7 +100,7 @@ public class QuestData { this.name = name0; if (userFormat != null) { - this.format = new GameFormatQuest(userFormat, allowSetUnlocks); + this.format = new GameFormatQuest(userFormat, allowSetUnlocks, null); } this.mode = mode0; this.achievements = new QuestAchievements(diff); diff --git a/forge-gui/src/main/java/forge/gamemodes/quest/setrotation/ISetRotation.java b/forge-gui/src/main/java/forge/gamemodes/quest/setrotation/ISetRotation.java new file mode 100644 index 00000000000..f477b7e05e1 --- /dev/null +++ b/forge-gui/src/main/java/forge/gamemodes/quest/setrotation/ISetRotation.java @@ -0,0 +1,11 @@ +package forge.gamemodes.quest.setrotation; + +import java.util.List; + +/** + * Supplies the current rotation of set codes based on the current quest state. + * Used for quest worlds that change their sets automatically over time. + */ +public interface ISetRotation { + public List getCurrentSetCodes(List allowedSetCodes); +} diff --git a/forge-gui/src/main/java/forge/gamemodes/quest/setrotation/QueueRandomRotation.java b/forge-gui/src/main/java/forge/gamemodes/quest/setrotation/QueueRandomRotation.java new file mode 100644 index 00000000000..bc52df6736f --- /dev/null +++ b/forge-gui/src/main/java/forge/gamemodes/quest/setrotation/QueueRandomRotation.java @@ -0,0 +1,48 @@ +package forge.gamemodes.quest.setrotation; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Random; +import forge.model.FModel; + +import static java.lang.Integer.min; + +/** + * A quest world rotation style where N random concurrent sets are available at any given time. + * S of these sets are rotated out after each set of W number of wins. + */ +public class QueueRandomRotation implements ISetRotation { + + private int concurrentSets; + private int rotateAfterWins; + private int setsPerRotation; + + @Override + public List getCurrentSetCodes(List allSets) { + if(FModel.getQuest() == null) + return allSets; + + // Each unique quest (based on name) gets its own unique set order + int seed = FModel.getQuest().getName().hashCode(); + Random rnd = new Random(seed); + List shuffledSets = new ArrayList<>(allSets); + Collections.shuffle(shuffledSets, rnd); + + List currentCodes = new ArrayList<>(); + int outRotations = FModel.getQuest().getAchievements().getWin() / rotateAfterWins; + int outRotated = outRotations * setsPerRotation; + int setsToAdd = min(concurrentSets, shuffledSets.size()); + for (int i = 0; i < setsToAdd; i++) { + int setToAdd = (i + outRotated) % shuffledSets.size(); + currentCodes.add(shuffledSets.get(setToAdd)); + } + return currentCodes; + } + + public QueueRandomRotation(int concurrentSets, int rotateAfterWins, int setsPerRotation){ + this.concurrentSets = concurrentSets; + this.rotateAfterWins = rotateAfterWins; + this.setsPerRotation = setsPerRotation; + } +}