diff --git a/Mage.Sets/src/mage/sets/AdventuresInTheForgottenRealms.java b/Mage.Sets/src/mage/sets/AdventuresInTheForgottenRealms.java index 7eafe71f6ba..35848fd8e56 100644 --- a/Mage.Sets/src/mage/sets/AdventuresInTheForgottenRealms.java +++ b/Mage.Sets/src/mage/sets/AdventuresInTheForgottenRealms.java @@ -31,7 +31,7 @@ public final class AdventuresInTheForgottenRealms extends ExpansionSet { this.numBoosterCommon = 10; this.numBoosterUncommon = 3; this.numBoosterRare = 1; - this.maxCardNumberInBooster = 275; + this.maxCardNumberInBooster = 281; cards.add(new SetCardInfo("+2 Mace", 1, Rarity.COMMON, mage.cards.p.Plus2Mace.class)); cards.add(new SetCardInfo("Aberrant Mind Sorcerer", 44, Rarity.UNCOMMON, mage.cards.a.AberrantMindSorcerer.class)); diff --git a/Mage.Sets/src/mage/sets/AmonkhetRemastered.java b/Mage.Sets/src/mage/sets/AmonkhetRemastered.java index cd79bced4b2..f827aca4a32 100644 --- a/Mage.Sets/src/mage/sets/AmonkhetRemastered.java +++ b/Mage.Sets/src/mage/sets/AmonkhetRemastered.java @@ -4,8 +4,6 @@ import mage.cards.ExpansionSet; import mage.constants.Rarity; import mage.constants.SetType; -import java.util.List; - /** * https://scryfall.com/sets/akr */ diff --git a/Mage.Sets/src/mage/sets/Dominaria.java b/Mage.Sets/src/mage/sets/Dominaria.java index cb6616a8c4e..c17f730bd99 100644 --- a/Mage.Sets/src/mage/sets/Dominaria.java +++ b/Mage.Sets/src/mage/sets/Dominaria.java @@ -1,15 +1,20 @@ package mage.sets; -import mage.cards.Card; import mage.cards.ExpansionSet; +import mage.cards.repository.CardCriteria; +import mage.cards.repository.CardInfo; +import mage.cards.repository.CardRepository; import mage.collation.BoosterCollator; import mage.collation.BoosterStructure; import mage.collation.CardRun; import mage.collation.RarityConfiguration; +import mage.constants.CardType; import mage.constants.Rarity; import mage.constants.SetType; +import mage.constants.SuperType; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; /** @@ -32,7 +37,9 @@ public final class Dominaria extends ExpansionSet { this.numBoosterCommon = 10; this.numBoosterUncommon = 3; this.numBoosterRare = 1; - this.ratioBoosterMythic = 8; + this.ratioBoosterMythic = 10; + this.ratioBoosterSpecialRare = 4; + this.ratioBoosterSpecialMythic = 5; this.maxCardNumberInBooster = 269; cards.add(new SetCardInfo("Academy Drake", 40, Rarity.COMMON, mage.cards.a.AcademyDrake.class)); @@ -317,10 +324,22 @@ public final class Dominaria extends ExpansionSet { cards.add(new SetCardInfo("Zhalfirin Void", 249, Rarity.UNCOMMON, mage.cards.z.ZhalfirinVoid.class)); } + // for sheet math reasons, four rare legendary creatures are collated as normal rares + // (a booster containing one of them will always contain an uncommon legend as well) + private static final List nonSpecialLegends = Arrays.asList("Darigaaz Reincarnated", "Josu Vess, Lich Knight", "Muldrotha, the Gravetide", "Shalai, Voice of Plenty"); + @Override - protected boolean boosterIsValid(List booster) { - return super.boosterIsValid(booster) - && booster.stream().anyMatch(card -> card.isLegendary() && card.isCreature()); + protected List findSpecialCardsByRarity(Rarity rarity) { + List cardInfos = super.findSpecialCardsByRarity(rarity); + cardInfos.addAll(CardRepository.instance.findCards(new CardCriteria() + .setCodes(this.code) + .rarities(rarity) + .supertypes(SuperType.LEGENDARY) + .types(CardType.CREATURE))); + cardInfos.removeIf(cardInfo -> ( + cardInfo.getCardNumberAsInt() > maxCardNumberInBooster + || nonSpecialLegends.contains(cardInfo.getName()))); + return cardInfos; } @Override @@ -339,7 +358,6 @@ class DominariaCollator implements BoosterCollator { private final CardRun uncommonA = new CardRun(true, "235", "119", "179", "145", "99", "38", "219", "175", "243", "33", "116", "210", "70", "160", "152", "81", "23", "235", "186", "242", "14", "130", "210", "54", "159", "121", "90", "38", "219", "180", "245", "23", "145", "179", "65", "186", "116", "82", "75", "121", "175", "99", "14", "119", "235", "70", "159", "130", "81", "54", "243", "160", "33", "82", "152", "210", "65", "180", "145", "90", "75", "242", "159", "99", "245", "116", "219", "70", "175", "119", "81", "65", "243", "186", "82", "38", "130", "235", "75", "160", "33", "121", "70", "152", "179", "90", "23", "145", "180", "54", "159", "116", "14", "65", "242", "179", "99", "38", "119", "210", "245", "180", "152", "23", "54", "243", "175", "90", "14", "130", "219", "242", "160", "121", "82", "75", "245", "186", "81", "33"); private final CardRun uncommonB = new CardRun(true, "231", "103", "188", "31", "64", "222", "249", "161", "28", "185", "150", "213", "97", "8", "181", "49", "220", "246", "188", "228", "56", "123", "218", "93", "185", "30", "74", "231", "244", "181", "31", "64", "128", "222", "107", "161", "137", "51", "213", "249", "103", "28", "49", "150", "220", "97", "188", "123", "56", "228", "137", "246", "30", "64", "244", "218", "107", "161", "128", "74", "213", "249", "93", "31", "51", "150", "222", "103", "185", "123", "56", "231", "97", "8", "220", "74", "137", "228", "107", "181", "150", "49", "218", "244", "93", "28", "51", "128", "213", "188", "8", "137", "64", "222", "246", "97", "30", "56", "31", "231", "103", "28", "123", "74", "220", "249", "161", "107", "246", "51", "228", "185", "8", "128", "49", "218", "244", "93", "30", "181"); private final CardRun uncommonLegend = new CardRun(true, "203", "109", "204", "66", "191", "4", "205", "111", "206", "12", "196", "165", "202", "69", "203", "113", "190", "109", "208", "25", "194", "148", "196", "12", "204", "66", "208", "111", "191", "165", "202", "4", "205", "113", "194", "148", "206", "25", "190", "69"); - // Shalai (35), Josu Vess (95), Darigaaz (193) and Muldrotha (199) are on the non-legend sheet; boosters containing one of them will also contain an uncommon legend private final CardRun rare = new CardRun(false, "6", "13", "18", "35", "39", "42", "55", "57", "61", "68", "88", "95", "98", "102", "114", "122", "129", "131", "133", "143", "147", "166", "173", "182", "183", "184", "187", "200", "201", "211", "214", "215", "217", "223", "233", "238", "239", "240", "241", "247", "248", "6", "13", "18", "35", "39", "42", "55", "57", "61", "68", "88", "95", "98", "102", "114", "122", "129", "131", "133", "143", "147", "166", "173", "182", "183", "184", "187", "200", "201", "211", "214", "215", "217", "223", "233", "238", "239", "240", "241", "247", "248", "1", "21", "100", "132", "193", "199", "207", "224", "237"); private final CardRun rareLegend = new CardRun(false, "16", "36", "58", "76", "96", "108", "146", "172", "192", "195", "198", "234", "16", "36", "58", "76", "96", "108", "146", "172", "192", "195", "198", "234", "26", "59", "86", "149", "174", "197"); private final CardRun land = new CardRun(false, "250", "251", "252", "253", "254", "255", "256", "257", "258", "259", "260", "261", "262", "263", "264", "265", "266", "267", "268", "269"); diff --git a/Mage.Sets/src/mage/sets/InnistradCrimsonVow.java b/Mage.Sets/src/mage/sets/InnistradCrimsonVow.java index 060896a2851..136cd237778 100644 --- a/Mage.Sets/src/mage/sets/InnistradCrimsonVow.java +++ b/Mage.Sets/src/mage/sets/InnistradCrimsonVow.java @@ -1,9 +1,12 @@ package mage.sets; +import mage.cards.Card; import mage.cards.ExpansionSet; import mage.constants.Rarity; import mage.constants.SetType; +import java.util.List; + /** * @author TheElk801 */ @@ -25,7 +28,10 @@ public final class InnistradCrimsonVow extends ExpansionSet { this.numBoosterUncommon = 3; this.numBoosterRare = 1; this.ratioBoosterMythic = 8; + this.ratioBoosterSpecialRare = 5.5; + this.ratioBoosterSpecialMythic = 5.4; // 5 mythic DFCs, 11 rare DFCs this.numBoosterDoubleFaced = 1; + this.maxCardNumberInBooster = 277; cards.add(new SetCardInfo("Abrade", 139, Rarity.COMMON, mage.cards.a.Abrade.class)); cards.add(new SetCardInfo("Adamant Will", 1, Rarity.COMMON, mage.cards.a.AdamantWill.class)); @@ -339,4 +345,10 @@ public final class InnistradCrimsonVow extends ExpansionSet { cards.add(new SetCardInfo("Wrathful Jailbreaker", 184, Rarity.COMMON, mage.cards.w.WrathfulJailbreaker.class)); cards.add(new SetCardInfo("Wretched Throng", 91, Rarity.COMMON, mage.cards.w.WretchedThrong.class)); } + + // add common double faced card to booster + @Override + protected void addDoubleFace(List booster) { + addToBooster(booster, getSpecialCardsByRarity(Rarity.COMMON)); + } } diff --git a/Mage.Sets/src/mage/sets/InnistradMidnightHunt.java b/Mage.Sets/src/mage/sets/InnistradMidnightHunt.java index 1728d60fc35..3f994791efc 100644 --- a/Mage.Sets/src/mage/sets/InnistradMidnightHunt.java +++ b/Mage.Sets/src/mage/sets/InnistradMidnightHunt.java @@ -1,5 +1,6 @@ package mage.sets; +import mage.cards.Card; import mage.cards.ExpansionSet; import mage.collation.BoosterCollator; import mage.collation.BoosterStructure; @@ -32,7 +33,10 @@ public final class InnistradMidnightHunt extends ExpansionSet { this.numBoosterUncommon = 3; this.numBoosterRare = 1; this.ratioBoosterMythic = 8; + this.ratioBoosterSpecialRare = 5.5; + this.ratioBoosterSpecialMythic = 5.4; // 5 mythic DFCs, 11 rare DFCs this.numBoosterDoubleFaced = 1; + this.maxCardNumberInBooster = 277; cards.add(new SetCardInfo("Abandon the Post", 127, Rarity.COMMON, mage.cards.a.AbandonThePost.class)); cards.add(new SetCardInfo("Adeline, Resplendent Cathar", 1, Rarity.RARE, mage.cards.a.AdelineResplendentCathar.class, NON_FULL_USE_VARIOUS)); @@ -506,6 +510,12 @@ public final class InnistradMidnightHunt extends ExpansionSet { cards.add(new SetCardInfo("Wrenn and Seven", 278, Rarity.MYTHIC, mage.cards.w.WrennAndSeven.class, NON_FULL_USE_VARIOUS)); } + // add common double faced card to booster + @Override + protected void addDoubleFace(List booster) { + addToBooster(booster, getSpecialCardsByRarity(Rarity.COMMON)); + } + @Override public BoosterCollator createCollator() { return new InnistradMidnightHuntCollator(); diff --git a/Mage.Sets/src/mage/sets/WarOfTheSpark.java b/Mage.Sets/src/mage/sets/WarOfTheSpark.java index 67c0da9674c..bb486b5cbb9 100644 --- a/Mage.Sets/src/mage/sets/WarOfTheSpark.java +++ b/Mage.Sets/src/mage/sets/WarOfTheSpark.java @@ -1,12 +1,14 @@ package mage.sets; -import mage.MageObject; -import mage.cards.Card; import mage.cards.ExpansionSet; +import mage.cards.repository.CardCriteria; +import mage.cards.repository.CardInfo; +import mage.cards.repository.CardRepository; import mage.collation.BoosterCollator; import mage.collation.BoosterStructure; import mage.collation.CardRun; import mage.collation.RarityConfiguration; +import mage.constants.CardType; import mage.constants.Rarity; import mage.constants.SetType; @@ -29,7 +31,9 @@ public final class WarOfTheSpark extends ExpansionSet { this.numBoosterCommon = 10; this.numBoosterUncommon = 3; this.numBoosterRare = 1; - this.ratioBoosterMythic = 8; + this.ratioBoosterMythic = (40 + 40 + 12) / 12.0; // non-planeswalkers: 40 rares, 12 mythics + this.ratioBoosterSpecialRare = 4; + this.ratioBoosterSpecialMythic = (13 + 13 + 3) / 3.0; // planeswalkers: 13 rares, 3 mythics this.maxCardNumberInBooster = 264; cards.add(new SetCardInfo("Ahn-Crop Invader", 113, Rarity.COMMON, mage.cards.a.AhnCropInvader.class)); @@ -346,9 +350,14 @@ public final class WarOfTheSpark extends ExpansionSet { } @Override - protected boolean boosterIsValid(List booster) { - return super.boosterIsValid(booster) - && booster.stream().filter(MageObject::isPlaneswalker).count() == 1; + protected List findSpecialCardsByRarity(Rarity rarity) { + List cardInfos = super.findSpecialCardsByRarity(rarity); + cardInfos.addAll(CardRepository.instance.findCards(new CardCriteria() + .setCodes(this.code) + .rarities(rarity) + .types(CardType.PLANESWALKER))); + cardInfos.removeIf(cardInfo -> cardInfo.getCardNumberAsInt() > maxCardNumberInBooster); + return cardInfos; } @Override diff --git a/Mage/src/main/java/mage/cards/ExpansionSet.java b/Mage/src/main/java/mage/cards/ExpansionSet.java index 169a27541a5..8c1d4df6846 100644 --- a/Mage/src/main/java/mage/cards/ExpansionSet.java +++ b/Mage/src/main/java/mage/cards/ExpansionSet.java @@ -115,9 +115,21 @@ public abstract class ExpansionSet implements Serializable { protected int numBoosterSpecial; protected int numBoosterLands; - protected int ratioBoosterSpecialLand = 0; // if > 0 basic lands are replaced with special land with probability ratioBoosterSpecialLandNumerator / ratioBoosterSpecialLand + + // if ratioBoosterSpecialLand > 0, one basic land may be replaced with a special card + // with probability ratioBoosterSpecialLandNumerator / ratioBoosterSpecialLand + protected int ratioBoosterSpecialLand = 0; protected int ratioBoosterSpecialLandNumerator = 1; - protected int ratioBoosterSpecialCommon = 0; // if > 0 one common is replaced with special card with probability 1 / ratioBoosterSpecialCommon + + // if ratioBoosterSpecialCommon > 0, one common may be replaced with a special card + // with probability 1 / ratioBoosterSpecialCommon + protected int ratioBoosterSpecialCommon = 0; + + // if ratioBoosterSpecialRare > 0, one uncommon or rare is always replaced with a special card + // probability that a rare rather than an uncommon is replaced is 1 / ratioBoosterSpecialRare + // probability that the replacement card for a rare is a mythic is 1 / ratioBoosterSpecialMythic + protected double ratioBoosterSpecialRare = 0; + protected double ratioBoosterSpecialMythic; protected int numBoosterCommon; protected int numBoosterUncommon; @@ -368,6 +380,10 @@ public abstract class ExpansionSet implements Serializable { return ratioBoosterMythic > 0 && ratioBoosterMythic * RandomUtil.nextDouble() <= 1; } + protected boolean checkSpecialMythic() { + return ratioBoosterSpecialMythic > 0 && ratioBoosterSpecialMythic * RandomUtil.nextDouble() <= 1; + } + public List tryBooster() { List booster = new ArrayList<>(); if (!hasBoosters) { @@ -398,18 +414,29 @@ public abstract class ExpansionSet implements Serializable { addToBooster(booster, commons); } + int numUncommonsToGenerate = numBoosterUncommon; + int numRaresToGenerate = numBoosterRare; + if (ratioBoosterSpecialRare > 0) { + Rarity specialRarity = Rarity.UNCOMMON; + if (ratioBoosterSpecialRare * RandomUtil.nextDouble() <= 1) { + specialRarity = (checkSpecialMythic() ? Rarity.MYTHIC : Rarity.RARE); + --numRaresToGenerate; + } else { + --numUncommonsToGenerate; + } + addToBooster(booster, getSpecialCardsByRarity(specialRarity)); + } + List uncommons = getCardsByRarity(Rarity.UNCOMMON); - for (int i = 0; i < numBoosterUncommon; i++) { + for (int i = 0; i < numUncommonsToGenerate; i++) { addToBooster(booster, uncommons); } - List rares = getCardsByRarity(Rarity.RARE); - List mythics = getCardsByRarity(Rarity.MYTHIC); - for (int i = 0; i < numBoosterRare; i++) { - if (checkMythic()) { - addToBooster(booster, mythics); - } else { - addToBooster(booster, rares); + if (numRaresToGenerate > 0) { + List rares = getCardsByRarity(Rarity.RARE); + List mythics = getCardsByRarity(Rarity.MYTHIC); + for (int i = 0; i < numRaresToGenerate; i++) { + addToBooster(booster, checkMythic() ? mythics : rares); } }