Introduce Evolving Wilds quest world. It has a random selection of legal core- and expansion sets that rotate periodically based on the number of wins.

This commit is contained in:
Robbatog
2022-11-04 15:48:52 +01:00
parent ed9931213c
commit 2968d7e5e2
7 changed files with 129 additions and 3 deletions

View File

@@ -558,6 +558,10 @@ public class GameFormat implements Comparable<GameFormat> {
return this.map.get("Modern");
}
public GameFormat getVintage() {
return this.map.get("Vintage");
}
public GameFormat getFormat(String format) {
return this.map.get(format);
}

View File

@@ -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

View File

@@ -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<QuestWorld>{
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<QuestWorld>{
FModel.getFormats().getFormat("Commander").getBannedCardNames(),false);
}
if (useName.equalsIgnoreCase(QuestWorld.EVOLVINGWILDSWORLDNAME)){
ISetRotation rot = new QueueRandomRotation(6, 5, 1);
List<String> 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); }

View File

@@ -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<String> getAllowedSetCodes() {
if(setRotation != null)
return setRotation.getCurrentSetCodes(super.getAllowedSetCodes());
return super.getAllowedSetCodes();
}
@Override
public Predicate<PaperCard> getFilterRules() {
// Filter must be continuously rebuilt if the format is mutable
if(setRotation != null)
return super.buildFilter(false);
return super.getFilterRules();
}
@Override
public Predicate<PaperCard> 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<String> setsToAllow, final List<String> cardsToBan) {
super(newName, setsToAllow, cardsToBan);
allowUnlocks = false;
setRotation = null;
}
public GameFormatQuest(final String newName, final List<String> setsToAllow, final List<String> 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<String> setsToAllow, final List<String> 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;
}
/**

View File

@@ -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);

View File

@@ -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<String> getCurrentSetCodes(List<String> allowedSetCodes);
}

View File

@@ -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<String> getCurrentSetCodes(List<String> 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<String> shuffledSets = new ArrayList<>(allSets);
Collections.shuffle(shuffledSets, rnd);
List<String> 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;
}
}